XML 名稱空間(XML Namespaces)介紹以及節點讀取方法
預設的名稱空間(Default Namespaces)
為元素定義預設的名稱空間可以讓我們省去在所有的子元素中使用字首的工作。
請使用下面的語法:
xmlns="namespaceURI"
這個 XML 文件攜帶著某個表格中的資訊:
<table xmlns="http://www.w3.org/TR/html4/"
>
<tr>
<td>Apples</td>
<td>Bananas</td>
</tr>
</table>
此 XML 文件攜帶著有關一件傢俱的資訊:
<tablexmlns="http://www.w3school.com.cn/furniture"
> <name>African Coffee Table</name> <width>80</width> <length>120</length> </table> (轉原文http://www.cnblogs.com/mgen/archive/2011/05/24/2056025.html)
眾所周知,XmlDocument可以進行XPath查詢,但實際上這裡所說的XPath查詢僅限於沒有名稱空間(沒有xmlns屬性)的XML,一旦遇到有名稱空間的XML,對應XPath查詢都會無結果。
比如下面這個XML
<a
<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