【问题标题】:Adding namespace attribute to XElement - how to prevent blank/empty namespace on child elements?向 XElement 添加命名空间属性 - 如何防止子元素上的空白/空命名空间?
【发布时间】:2011-03-17 11:29:44
【问题描述】:

我需要将 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>

如何防止将空白/空命名空间添加到已应用所需命名空间的元素的每个子元素中?

【问题讨论】:

    标签: vb.net linq-to-xml xml-namespaces xelement


    【解决方案1】:

    从For 循环中删除Elements,它也会导致处理所有子元素。

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

    编辑

    抱歉,你注意到了,我还没有喝咖啡。

    .Net 这样做的原因是因为您正在重置文档中间的默认命名空间。如果它没有将空命名空间附加到子元素,那么&lt;Segments&gt; 的所有子元素将自动成为http://myurl 命名空间的一部分。也许这是您想要的结果,但由于您没有告诉 .Net,它假设您不这样做。

    换一种说法,您得到的输出表明&lt;Itinerary&gt; 在empty 命名空间中,&lt;Segments&gt; 在http://myurl 命名空间中,&lt;SegmentFlight&gt; 在同一个@987654331 中@命名空间为&lt;Itinerary&gt;。如果您希望 &lt;SegmentFlight&gt; 成为与 &lt;Segments&gt; 相同的命名空间的一部分,那么您需要递归地应用命名空间。当您调用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>
    

    【讨论】:

    • 不,这不太行,如果我删除Elements,那么只会选择顶级“行程”元素。在循环中使用Elements,选择正确的“Segments”、“References”等元素。
    • 酷,有道理,我试试看。我也在考虑将我的命名空间应用到顶部 Itinerary 节点,但我认为我需要为命名空间分配一个自定义前缀,然后将该前缀应用到下面的所有子元素...?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多