当我想使用XPath遍历我的XmlDocument时,我遇到了文档中有许多丑陋的命名空间的问题,所以我开始使用NamespaceManager
和XPath。
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)是空名称空间。
为什么?而且,更重要的是:如何访问默认命名空间中的节点,如果不使用前缀将它们设置为空命名空间?
如果我在搜索节点时甚至无法访问它,那么在管理器上设置默认命名空间有什么用呢?
答案 0 :(得分:5)
使用表达式上下文中的名称空间声明,将节点测试中的QName扩展为扩展名。 这与开始和结束标记中的元素类型名称的扩展相同,除了未使用xmlns声明的默认命名空间:如果QName没有前缀,则名称空间URI为null(这与扩展属性名称的方式相同)。如果QName具有在表达式上下文中没有名称空间声明的前缀,则会出错。
所以这不是关于NamespaceManager
的问题,而是定义XPath的工作方式。
您缺少的一点是您在NamespaceManager
中使用的前缀不一定与XML文档中的前缀类似。如果需要,您可以使用xcel
urn:schemas-microsoft-com:office:excel
前缀,sp
使用urn:schemas-microsoft-com:office:spreadsheet
前缀。实际上,您已经在命名空间管理器中为该URN分配了一个前缀,因此您可以使用它:
foreach (XmlNode row in
document.SelectNodes("/ss:Workbook/ss:Worksheet[1]/ss:Table/ss:Row", manager))
关于这个问题:
如果我在搜索节点时甚至无法访问它,那么在管理器上设置默认命名空间有什么用?
好处是XmlNamespaceManager
不仅用于评估XPath。例如,它可用于跟踪XML文档中的命名空间,其中存在默认命名空间的概念。
答案 1 :(得分:2)
我无法回答你的最后一个问题(&#34;有什么好处......&#34;)除非它可能有助于非XPath情况。但关于&#34;如何访问默认命名空间中的节点,如果不使用前缀将它们设置为空命名空间?&#34;,答案是你必须使用前缀。
因此,在这种情况下,由于您将前缀ss
声明为绑定到URI为urn:schemas-microsoft-com:office:spreadsheet
的命名空间(与默认命名空间相同的命名空间),因此您可以使用{{ XPath表达式中的1}}前缀:
ss
答案 2 :(得分:2)
@ JLRishe的答案对于访问默认命名空间中的节点是正确的(即始终将前缀映射到XmlNamespaceManager
中的默认命名空间)。
从引号(MSDN XmlNamespaceManager.AddNamespace)中读取链接的整个上下文,声明在XPath表达式中不使用默认的“empty”前缀。
前缀 键入:System.String
与要添加的命名空间关联的前缀。使用String.Empty添加默认命名空间。&gt;
注意如果XmlNamespaceManager将用于解析XML路径语言(XPath)表达式中的名称空间,则必须指定前缀。如果XPath表达式不包含前缀,则假定名称空间统一资源标识符(URI)是空名称空间。有关XPath表达式和XmlNamespaceManager的更多信息,请参阅XmlNode.SelectNodes和XPathExpression.SetContext方法。
答案 3 :(得分:0)
我发现如果删除默认命名空间
的xmlns =&#34;瓮:架构 - 微软-COM:办公室:电子表格&#34; &lt; -delete it
或使默认命名空间为null
的xmlns =&#34;&#34;
使用XPath进行搜索时,它不需要在没有名称空间&#34;之前添加名称空间到XPath。
那么,默认名称空间声明是否非常重要,?
如果没有,我可能会删除默认的命名空间声明,它使得使用XPath更容易搜索,因为不需要像往常一样添加命名空间。
我尝试过另一种方法是添加名称为&#34;默认&#34;的默认命名空间。由我自己提供,
我写了一个方法,可以自动添加&#34;默认&#34;没有其他命名空间的元素:
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&#34;
到
&#34;默认:AA / XX:CC /默认:DD / HH:GG /默认:BB&#34;