在 XML 中,元素名稱是由開發者定義的,當兩個不同的文件使用相同的元素名稱時,就會發生命名衝突。
這個XML 文件攜帶著某個表格中的信息:
<tr> <td>Apples</td> <td>Bananas</td> </tr>
這個XML 文件攜帶有關桌子的信息(一件家具):
<name>African Coffee Table</name> <width>80</width> <length>120</length>
假如這兩個XML 文件被一起使用,由於兩個文件都包含帶有不同內容和定義的
此XML 文件攜帶著有關一件家具的信息:
眾所周知,XmlDocument可以進行XPath查詢,但實際上這裡所說的XPath查詢僅限於沒有命名空間(沒有xmlns屬性)的XML,一旦遇到有命名空間的XML,對應XPath查詢都會無結果。
例如下面這個XML
<a xmlns="mgen.cnblogs.com"> <b>ccc</b> </a>
XPath查詢/a/b會回傳null,而如果沒有xmlns的話,會回傳節點b。
If the XPath expression does not include a prefix, it is assumed that the namespace URI is the empty namespace. If your XML includes a default namespace, you must still add a prefix and namespace URI to the XmlNamespaceManager; otherwise, you will not get any nodes selected
意思就是如果XPath表達式沒有加上前綴(如a:b中前綴是a),那麼所查詢節點(注意屬性也可以是節點)的命名空間URI就應該是空值(也是預設值),否則XPath不會回傳結果。
上面的XML, 因為節點a和b都有命名空間值,自然XPath查詢不會有結果。
(上面英文也提到如果節點有預設命名空間,那麼還得手動在XmlNamespaceManager中加入前綴和命名空間值,這個在後面會講的)
在看解決方案前,首先需要能夠辨識XML命名空間,當然辨識XML命名空間值還是很容易的,參考如下XML(這個XML在後面程式中也會用到)
<?xmlversion="1.0" encoding="utf-8"?> <rootxmlns="dotnet" xmlns:w="wpf"> <a>data in a</a> <w:b>data in b</w:b> <cxmlns="silverlight"> <w:d> <e>data in e</e> </w:d> </c> </root>
它的所有XML節點的命名空間如下所示:
<?xmlversion="1.0" encoding="utf-8"?> <rootxmlns="dotnet" xmlns:w="wpf"> <!-- xmlns: dotnet --> <a>data in a</a> <!-- xmlns: dotnet --> <w:b>data in b</w:b> <!-- xmlns: wpf --> <cxmlns="silverlight"> <!-- xmlns: silverlight --> <w:d> <!-- xmlns: wpf --> <e>data in e</e> <!-- xmlns: silverlight --> </w:d> </c> </root>
如果識別XML命名空間沒有問題,那麼後面的操作就相當簡單了,你需要記住:在XmlDocument中用XPath查詢某一節點時,只要它的命名空間值不是空值,那麼你必須給它一個前綴, 用這個前綴代表這個節點的命名空間值!這些前綴是透過XmlNamespaceManager類別新增的,使用時將XmlNamespaceManager 傳入SelectNodes或SelectSingleNode中即可。這也是為什麼上面說「如果節點有預設命名空間,那麼還得手動在 XmlNamespaceManager中加入前綴和命名空間值」的原因。
另外构造一个XmlNamespaceManager需要XmlNameTable对象,这个对象可以从XmlDocument.NameTable和XmlReader.NameTable属性中得到。
下面我们步入代码,比如说查询上面XML中的节点e,分析位置节点e位于:root->c->d->e,然后将所需命名空间值加入到 XmlNamespaceManager中(前缀名称无所谓,只要在XPath一致即可),查询即可成功,如下代码:
/* * 假设上面XML文件在C:\a.txt中 * 下面代码会查询目标节点e,并输出数据:data in e * */ var xmlDoc =newXmlDocument(); xmlDoc.Load(@"C:\a.txt"); //加入命名空间和前缀 var xmlnsm =newXmlNamespaceManager(xmlDoc.NameTable); xmlnsm.AddNamespace("d", "dotnet"); xmlnsm.AddNamespace("s", "silverlight"); xmlnsm.AddNamespace("w", "wpf"); var node = xmlDoc.SelectSingleNode("/d:root/s:c/w:d/s:e", xmlnsm); Console.WriteLine(node.InnerText); //输出:data in e
以上是詳解XML命名空間(XML Namespaces)介紹以及節點讀取方法的範例程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!