2014-10-29 70 views
4

當我想使用XPath遍歷我的XmlDocument時,我遇到了文檔中存在許多醜陋命名空間的問題,因此我開始使用NamespaceManager以及XPath 。爲什麼在XPath中使用無前綴時NamespaceManager不使用DefaultNamespace

的XML看起來像這樣

<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" 
xmlns:o="urn:schemas-microsoft-com:office:office" 
xmlns:x="urn:schemas-microsoft-com:office:excel" 
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" 
xmlns:html="http://www.w3.org/TR/REC-html40"> 
    <Worksheet ss:Name="KA0100401"> 
     <Table> 
      <Row> 
       <Cell>Data</Cell> 
      </Row> 
      <!-- more rows... --> 
     </Table> 
    </Worksheet> 
    <Worksheet ss:Name="KA0100402"> 
     <!-- .... ---> 
    </Worksheet> 
</Workbook> 

現在,從我從這份文件看,"urn:schemas-microsoft-com:office:spreadsheet"是默認的命名空間,因爲它所在的根元素。

所以,天真,我配置了我NamespaceManager這樣的:

XmlDocument document = new XmlDocument(); 
document.Load(reader); 
XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable); 
manager.AddNamespace(String.Empty, "urn:schemas-microsoft-com:office:spreadsheet"); 
manager.AddNamespace("o", "urn:schemas-microsoft-com:office:office"); 
manager.AddNamespace("x", "urn:schemas-microsoft-com:office:excel"); 
manager.AddNamespace("ss", "urn:schemas-microsoft-com:office:spreadsheet"); 
manager.AddNamespace("html", "http://www.w3.org/TR/REC-html40"); 

但是,當我嘗試訪問節點

foreach (XmlNode row in document.SelectNodes("/Workbook/Worksheet[1]/Table/Row", manager)) 

我從來沒有得到任何結果。我的印象是,通過將第一個名稱空間設置爲空前綴,我不需要在該工作空間中搜索節點時設置它。

但是,因爲它是stated on the AddNamespace method

如果XPath表達式不包括一個前綴,假定命名空間統一資源標識符(URI)是空的命名空間。

這是爲什麼?而且,更重要的是:如何在默認名稱空間中訪問節點,如果不使用前綴將它們設置爲空名稱空間?

如果在搜索節點時甚至無法訪問管理器,那麼在管理器上設置默認名稱空間有什麼好處?

+1

「有什麼好處?」 - 有它沒有想到你該'XmlNamespaceManager'所使用的多段代碼*只是使用它的XPath查詢和* *這些情況下默認的命名空間*可能是完全有用的比? – 2014-10-29 14:16:28

+0

可能重複:http://stackoverflow.com/questions/585812/using-xpath-with-default-namespace-in-c-sharp @Damien:無需是不禮貌的。 – LarsH 2014-10-29 14:51:26

+1

@LarsH - 這是一種修辭手段。我對不起你認爲這是不禮貌的,我經常使用註釋這種風格讓人質疑他們的假設,這是第一次有人曾斷言,這是不禮貌的。對不起,這引起了你的進攻。 – 2014-10-29 15:06:22

回答

2

@ JLRishe的答案對於訪問默認命名空間中的節點是正確的(即總是將前綴映射到XmlNamespaceManager中的默認命名空間)。

從報價中讀取鏈接的整個上下文(MSDN XmlNamespaceManager.AddNamespace),聲明在XPath表達式中不使用默認的「空白」前綴。

前綴 類型:System

與正在添加的命名空間相關聯的前綴。使用的String.Empty添加默認的命名空間。>

如果XmlNamespaceManager的將被用於在XML路徑語言解析名稱空間(的XPath)表達式,前綴必須指定。如果XPath表達式不包含前綴,則假定名稱空間統一資源標識符(URI)是空的名稱空間。有關XPath表達式和XmlNamespaceManager的更多信息,請參閱XmlNode.SelectNodes和XPathExpression.SetContext方法。

5

XPath 1.0 spec

的QName在節點測試是使用命名空間聲明從表達式上下文擴展成一個擴展名。 這與開始和結束標籤中元素類型名稱的擴展方式相同,不同之處在於不使用用xmlns聲明的默認名稱空間:如果QName沒有前綴,則名稱空間URI爲null(this與擴展屬性名稱的方式相同)。如果QName具有在表達式上下文中沒有名稱空間聲明的前綴,那是錯誤的。

所以這不是關於NamespaceManager的問題,而是XPath被定義爲工作的方式。


您缺少的一點是您在NamespaceManager中使用的前綴不必與XML文檔中的前綴類似。如果需要,可以使用xcel前綴urn:schemas-microsoft-com:office:excelurn:schemas-microsoft-com:office:spreadsheet前綴sp。事實上,你已經指定爲您的命名空間管理器,URN前綴,所以你可以使用:

foreach (XmlNode row in 
     document.SelectNodes("/ss:Workbook/ss:Worksheet[1]/ss:Table/ss:Row", manager)) 


對於這個問題:

什麼好處設置默認如果我在搜索節點時甚至無法訪問它,那麼管理器上的名稱空間?

好的是,XmlNamespaceManager不僅僅用於評估XPath。例如,它可用於跟蹤XML文檔中的名稱空間,其中存在默認名稱空間的概念。

2

我無法回答你最後一個問題(「有什麼好處......」),除非在非XPath情況下有幫助。但關於「如何訪問默認命名空間中的節點,如果不使用前綴將它們設置爲空的命名空間?」,答案是您必須使用前綴。

在這種情況下

所以,既然你聲明的前綴ss作爲被綁定到其URI是urn:schemas-microsoft-com:office:spreadsheet命名空間,這是同一個命名空間作爲默認的命名空間,你可以只使用ss前綴您的XPath表達式:

foreach (XmlNode row in document.SelectNodes("/ss:Workbook/ss:Worksheet[1]/ss:Table/ss:Row", 
    manager)) 
0

我發現,如果你刪除默認命名空間

的xmlns = 「甕:架構 - 微軟COM:辦公室:電子表格」 < -delete它

或使默認命名空間空

的xmlns = 「」

使用XPath進行搜索時,無需在「沒有命名空間的元素」之前將命名空間添加到XPath中。

那麼,是默認的命名空間聲明非常重要的,?

如果沒有,我可以刪除默認的命名空間聲明,它使得使用XPath搜索更容易,因爲不需要添加名字空間如常。

我曾嘗試另一種方式是添加默認的命名空間的名稱「默認」,這由我自己放棄,

和我寫的,可以自動添加「默認」的元素沒有其他命名空間的方法:

public static string XPathAddDeafultNameSpaceProccess(this string XPathProcess) 
     { 
      string[] XPSplit = XPathProcess.Split('/'); 

      for (int i = 0; i < XPSplit.Length; i++)//if element no namespace, add default 
      { 
       if (!XPSplit[i].Contains(':') && !XPSplit[i].Contains('@')) 
        XPSplit[i] = "default:" + XPSplit[i]; 
      } 
      for (int i = 0; i < XPSplit.Length; i++) 
      { 
       if (i != XPSplit.Length - 1)//if not the last, add"/"      
       XPSplit[i] += "/"; 
      } 

      string output = ""; 
      foreach (string s in XPSplit)//combine 
       output += s; 
      return output; 
     } 

它可以打開

AA/XX:立方厘米/ DD/HH:GG/BB」

「默認:AA/XX:CC /默認:DD/HH:GG /默認:BB」

相關問題