2012-08-28 174 views
1

我正在使用Linq解析XML文本到XML。返回的XDocument將所有這些命名空間添加到了我的每個節點,並且使得發現後代不可能,或者至少,我對「地標」的搜索不起作用,很可能是因爲kml:Placemark不適合搜索。XDocument.Parse向節點添加名稱空間

當我在單元測試中用基本的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> 
+0

你看,它是有設計的。因此,您需要將名稱空間與元素名稱連接起來才能執行成功搜索。 – Oleg

+0

我不明白爲什麼KML是由GE創建的,它指定了命名空間,但命名空間是自動解釋的,並沒有明確地放在每個節點中。我猜XDocument需要在讀取時明確命名空間,但是它能以某種方式自行確定它? –

+0

不是[xmlns =「http://www.opengis.net/kml/2.2」表示默認命名空間嗎? –

回答

2

我想您所遇到的LINQ的缺點,以XML數據模型,它不存儲元素的前綴部分或在其模型屬性名稱,而不是簡單地存儲空間聲明屬性(例如xmlns="..."xmlns:pf="..."),然後在序列化對象樹進行標記時,它會嘗試推斷元素和屬性的前綴。在您的示例中,名稱空間http://www.opengis.net/kml/2.2定義了兩次,一次是作爲缺省名稱空間的xmlns="http://www.opengis.net/kml/2.2",一次是前綴kmlxmlns: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正確的方式XML與DescendantsElementsElement方法訪問它們是通過使用XNamespace的級聯與string來構建XName例如

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

似乎Google Earth創建了它的KML(XML)文件,NS由於某種原因定義了兩次,是不幸的,是的,你在動態構建它,以便從根目錄獲得命名空間,無論NS實際是什麼,都可以解析它。 –

0

使用本

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