Добавяне на атрибут за пространство от имена към XElement - как да се предотврати празно/празно пространство от имена на дъщерни елементи?

Трябва да прочета xml документ от запис в база данни в обект XDocument, за да бъде десериализиран. За да работи десериализацията, трябва да приложа конкретно пространство от имена към всеки от елементите от ниво 1. И така XML изглежда малко по следния начин:

<Itinerary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Segments>
        <SegmentFlight>
        </SegmentFlight>
        <!-- more child elements -->
    </Segments>
    <References>
        <!-- child elements -->
    </References>
    <Fares>
        <!-- child elements -->
    </Fares>
</Itinerary>

И трябва да изглежда така:

<Itinerary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Segments xmlns="http://myurl">
        <SegmentFlight>
        </SegmentFlight>
        <!-- more child elements -->
    </Segments>
    <References xmlns="http://myurl">
        <!-- child elements -->
    </References>
    <Fares xmlns="http://myurl">
        <!-- child elements -->
    </Fares>
</Itinerary>

Но когато стартирам следния код, за да приложа пространството от имена към всеки от елементите от най-високо ниво в рамките на възела на маршрута:

Dim xmlDoc As XDocument = XDocument.Load(New System.IO.StringReader(xmlStringFromDB))
Dim ns As XNamespace = "http://myurl"

For Each elem In xmlDoc.Descendants("Itinerary").Elements
    elem.Name = ns + elem.Name.LocalName
Next    

Получавам празен атрибут на пространство от имена xmln="" на всеки дъщерен елемент в този елемент, което води до неуспех на десериализацията:

<Itinerary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Segments xmlns="http://myurl">
        <SegmentFlight xmlns="">
            <!-- etc ... -->
        </Segments>

Как да предотвратя добавянето на празно/празно пространство от имена към всеки дъщерен елемент на елемента, към който е приложено необходимото пространство от имена?


person Marcus Guinane    schedule 17.03.2011    source източник


Отговори (1)


Премахнете Elements от вашия For цикъл, той също причиняваше обработка на всички дъщерни елементи.

    For Each elem In xmlDoc.Descendants("Itinerary") ''//.Elements
        elem.Name = ns + elem.Name.LocalName
    Next

РЕДАКТИРАНЕ

Съжалявам, това не проработи, както забелязахте, още не бях изпил кафето си.

Причината, поради която .Net прави това, е, че нулирате пространството от имена по подразбиране в средата на документ. Ако не добави празното пространство от имена към дъщерните елементи, тогава всички дъщерни елементи на <Segments> ще бъдат автоматично част от пространството от имена http://myurl. Може би това е резултатът, който искате, но тъй като не сте казали на .Net, предполагаме, че не го правите.

За да кажем това по различен начин, изходът, който получавате, казва, че <Itinerary> е в пространството от имена empty, <Segments> е в пространството от имена http://myurl и <SegmentFlight> е в същото пространство от имена empty като <Itinerary>. Ако искате <SegmentFlight> да бъде част от същото пространство от имена като <Segments>, тогава трябва рекурсивно да приложите пространството от имена. Когато извикате ToString() .Net ще изведе това, което очаквате. Ето една рекурсивна версия:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim xmlDoc As XDocument = XDocument.Load(New System.IO.StringReader(xmlStringFromDB))

    Dim ns As XNamespace = "http://myurl"
    ApplyNameSpaceToAllChildren(xmlDoc.Descendants("Itinerary").Elements(), ns)

    Trace.WriteLine(xmlDoc.ToString())
End Sub
Private Sub ApplyNameSpaceToAllChildren(ByVal elements As IEnumerable(Of XElement), ByVal ns As XNamespace)
    For Each elem In elements
        elem.Name = ns + elem.Name.LocalName
        If elem.HasElements Then
            ApplyNameSpaceToAllChildren(elem.Elements, ns)
        End If
    Next
End Sub

Това извежда:

<Itinerary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Segments xmlns="http://myurl">
    <SegmentFlight></SegmentFlight>
    <!-- more child elements -->
  </Segments>
  <References xmlns="http://myurl">
    <!-- child elements -->
  </References>
  <Fares xmlns="http://myurl">
    <!-- child elements -->
  </Fares>
</Itinerary>
person Chris Haas    schedule 17.03.2011
comment
Не, това не работи съвсем, ако премахна Elements, тогава ще бъде избран само елементът „Маршрут“ от най-високо ниво. С Elements в цикъла се избират правилните елементи „Сегменти“, „Препратки“ и т.н. - person Marcus Guinane; 17.03.2011
comment
Страхотно, има смисъл, ще го пробвам. Също така мислех да приложа моето пространство от имена към горния възел Itinerary, но мисля, че ще трябва да присвоя персонализиран префикс към пространството от имена и след това да приложа този префикс към всички дъщерни елементи по-долу ...? - person Marcus Guinane; 17.03.2011