【问题标题】:XDocument.Parse adds namespaces to nodesXDocument.Parse 向节点添加命名空间
【发布时间】:2012-08-28 12:52:05
【问题描述】:

我正在使用 Linq to XML 解析 XML 文本。返回的 XDocument 将所有这些命名空间添加到我的每个节点,并且无法找到后代,或者至少,我对“地标”的搜索不起作用,很可能是因为 kml:Placemark 不适合搜索。

当我在单元测试中使用基本的 XML 文件对此进行测试时,它运行良好。我猜 XML 声明部分没有所有的命名空间。

如何在不添加所有命名空间的情况下解析 XML 文本?

解析:

    XDocument document = XDocument.Parse(text);
    var polygonNodes = document.Descendants("Polygon"); // yields no nodes, even though there are descendants with this.

原始文件

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
    <name>poly1_philmont.kml</name>
    <Style id="s_ylw-pushpin_hl">
        <IconStyle>
            <scale>1.3</scale>
            <Icon>
                <href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
            </Icon>
            <hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/>
        </IconStyle>
        <LineStyle>
            <color>ff0000aa</color>
        </LineStyle>
        <PolyStyle>
            <color>33ffaa00</color>
        </PolyStyle>
    </Style>
... </kml>

用 XDocument(根节点)解析

<kml:kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
  <kml:Document>
    <kml:name>poly1_philmont.kml</kml:name>
    <kml:Style id="s_ylw-pushpin_hl">
      <kml:IconStyle>
        <kml:scale>1.3</kml:scale>
        <kml:Icon>
          <kml:href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</kml:href>
        </kml:Icon>
        <kml:hotSpot x="20" y="2" xunits="pixels" yunits="pixels" />
      </kml:IconStyle>
      <kml:LineStyle>
        <kml:color>ff0000aa</kml:color>
      </kml:LineStyle>
      <kml:PolyStyle>
        <kml:color>33ffaa00</kml:color>
      </kml:PolyStyle>
    </kml:Style>
...
</kml:kml>

【问题讨论】:

  • 你看,这是设计使然。因此,您需要将命名空间与元素名称连接起来才能成功执行搜索。
  • 我不明白为什么当GE创建KML时,它指定了命名空间,但命名空间是自动解释的,而不是明确地放在每个节点中。我猜 XDocument 需要在读取时明确命名它,但不知何故能够自行确定它?
  • 不是[xmlns="opengis.net/kml/2.2]表示默认命名空间吗?

标签: c# .net-3.5 linq-to-xml kml


【解决方案1】:

我认为您遇到了 LINQ to XML 数据模型的缺点,它不会在其模型中存储元素或属性名称的前缀部分,而是仅存储命名空间声明属性(例如 xmlns="..." 和 @ 987654322@),然后在将对象树序列化为标记时,它会尝试推断元素和属性的前缀。在您的示例中,命名空间 http://www.opengis.net/kml/2.2 定义了两次,一次是使用 xmlns="http://www.opengis.net/kml/2.2" 作为默认命名空间,一次使用前缀 kml (xmlns:kml="http://www.opengis.net/kml/2.2")。在这种情况下,推断元素名称前缀的尝试被破坏了,看起来实现将最后一个声明考虑在内

    string xml = @"<foo xmlns=""http://example.com/ns1"" xmlns:pf=""http://example.com/ns1""/>";

    XDocument doc = XDocument.Parse(xml);

    doc.Save(Console.Out);

输出

<pf:foo xmlns="http://example.com/ns1" xmlns:pf="http://example.com/ns1" />

同时

    string xml = @"<foo xmlns:pf=""http://example.com/ns1"" xmlns=""http://example.com/ns1""/>";

    XDocument doc = XDocument.Parse(xml);

    doc.Save(Console.Out);

输出

<foo xmlns:pf="http://example.com/ns1" xmlns="http://example.com/ns1" />

因此,除非您在创建输入时控制命名空间声明的顺序,否则您的输入 XML 与同一命名空间的两个命名空间声明可能不会与 XDocument 或 XElement 往返。

尽管如此,只要元素位于命名空间中,使用 LINQ to XML 使用 DescendantsElementsElement 方法访问它们的正确方法是使用 XNamespacestring 构造一个 XName 例如

XNamespace ns = doc.Root.Namespace;
IEnumerable<XElement> fooElements = doc.Descendants(ns + "foo");

【讨论】:

  • Google 地球似乎出于某种原因创建了其 KML (XML) 文件,其中 NS 定义了两次,这很不幸。是的,您在动态构建它以从根目录获取命名空间允许它解析而不管 NS 实际是什么。谢谢马丁。
【解决方案2】:

使用这个

XNamespace kmlNS = "http://www.opengis.net/kml/2.2";
XDocument document = XDocument.Parse(text);
var polygonNodes = document.Descendants(kmlNS+"Polygon");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 2016-07-08
    • 1970-01-01
    • 1970-01-01
    • 2017-06-13
    • 2011-04-28
    • 1970-01-01
    相关资源
    最近更新 更多