为什么NamespaceManager在XPath中不使用前缀时不使用DefaultNamespace

当我想使用XPath遍历我的XmlDocument时,我遇到了文档中有许多丑陋的命名空间的问题,所以我开始使用NamespaceManager和XPath。

XML看起来像这样

     Data  

现在,根据我在本文档中看到的, "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)) 

我从来没有得到任何结果。 我的印象是,通过使用空前缀设置第一个命名空间,在搜索该工作空间中的节点时,我不需要设置它。

但是,正如在AddNamespace方法中所述 :

如果XPath表达式不包含前缀,则假定名称空间统一资源标识符(URI)是空名称空间。

这是为什么? 而且,更重要的是:如何访问默认命名空间中的节点,如果不使用前缀将它们设置为空命名空间?

如果我在搜索节点时甚至无法访问它,那么在管理器上设置默认命名空间有什么用呢?

@ JLRishe的答案对于访问默认命名空间中的节点是正确的(即始终将前缀映射到XmlNamespaceManager的默认命名空间)。

从引用( MSDN XmlNamespaceManager.AddNamespace )读取链接的整个上下文,声明在XPath表达式中不使用默认的“empty”前缀。

prefix类型:System.String

与要添加的命名空间关联的前缀。 使用String.Empty添加默认命名空间。>

注意如果XmlNamespaceManager将用于解析XML路径语言(XPath)表达式中的名称空间,则必须指定前缀 。 如果XPath表达式不包含前缀,则假定名称空间统一资源标识符(URI)是空名称空间。 有关XPath表达式和XmlNamespaceManager的更多信息,请参阅XmlNode.SelectNodes和XPathExpression.SetContext方法。

从XPath 1.0规范 :

使用表达式上下文中的名称空间声明,将节点测试中的QName扩展为扩展名。 这与在start和end-tags中对元素类型名称进行扩展的方式相同, 只是不使用xmlns声明的默认命名空间 :如果QName没有前缀,则命名空间URI为null(这是相同的)方式属性名称被扩展)。 如果QName具有在表达式上下文中没有名称空间声明的前缀,则会出错。

所以这不是关于NamespaceManager的问题,而是定义XPath的工作方式。

您缺少的一点是您在NamespaceManager使用的前缀不必与XML文档中的前缀类似。 如果需要,可以使用urn:schemas-microsoft-com:office:excelxcel前缀,以及urn:schemas-microsoft-com:office:excel xcel urn:schemas-microsoft-com:office:spreadsheetsp前缀。 实际上,您已经在命名空间管理器中为该URN分配了一个前缀,因此您可以使用它:

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

关于这个问题:

如果我在搜索节点时甚至无法访问它,那么在管理器上设置默认命名空间有什么用呢?

好处是XmlNamespaceManager用于评估XPath。 例如,它可用于跟踪XML文档中的命名空间,其中存在默认命名空间的概念。

我无法回答你的最后一个问题(“有什么好处……”),除非它可能在非XPath情况下有所帮助。 但是关于“如何访问默认命名空间中的节点,如果不使用前缀将它们设置为空命名空间?”,答案是您必须使用前缀。

所以在这种情况下,由于您声明前缀ss绑定到URI为urn:schemas-microsoft-com:office:spreadsheet的命名空间urn:schemas-microsoft-com:office:spreadsheet ,它与默认命名空间的命名空间相同,因此您只需使用ss前缀即可。你的XPath表达式:

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

我发现如果删除默认命名空间

xmlns =“urn:schemas-microsoft-com:office:spreadsheet”<-delete it

或使默认命名空间为null

的xmlns = “”

使用XPath进行搜索时,在“没有命名空间的元素”之前,不需要将命名空间添加到XPath。

那么,默认名称空间声明真的很重要吗?

如果没有,我可能会删除默认的命名空间声明,它使得使用XPath更容易搜索,因为不需要像往常一样添加命名空间。

我试过另一种方法是添加一个名为“default”的默认命名空间,由我自己给出,

我写了一个方法,可以自动添加“默认”到没有其他命名空间的元素:

 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”