问题是该sitemapindex
元素定义了一个默认命名空间。选择节点时需要指定命名空间,否则找不到。例如:
XmlDocument xml = new XmlDocument();
xml.Load("sitemap.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("s", "http://www.sitemaps.org/schemas/sitemap/0.9");
XmlNodeList xnList = xml.SelectNodes("/s:sitemapindex/s:sitemap", manager);
通常来说,使用 时XmlNameSpaceManager
,您可以将前缀保留为空字符串,以指定您希望该命名空间成为默认命名空间。所以你会认为你可以做这样的事情:
// WON'T WORK
XmlDocument xml = new XmlDocument();
xml.Load("sitemap.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("", "http://www.sitemaps.org/schemas/sitemap/0.9"); //Empty prefix
XmlNodeList xnList = xml.SelectNodes("/sitemapindex/sitemap", manager); //No prefixes in XPath
但是,如果您尝试该代码,您会发现它找不到任何匹配的节点。原因是在 XPath 1.0(这是 XmlDocument 实现的)中,当没有提供命名空间时,它总是使用空命名空间,而不是默认命名空间。因此,无论您是否在 中指定默认名称空间,XmlNamespaceManager
XPath 都不会使用它。引用Official XPath Specification中的相关段落:
使用来自表达式上下文的命名空间声明将节点测试中的 QName 扩展为扩展名称。这与对开始和结束标记中的元素类型名称进行扩展的方式相同,只是不使用使用 xmlns 声明的默认命名空间:如果 QName 没有前缀,则命名空间 URI 为空(这是相同的方式属性名称被扩展)。如果 QName 具有在表达式上下文中没有名称空间声明的前缀,则这是一个错误。
因此,当您正在阅读的元素属于某个名称空间时,您无法避免将名称空间前缀放在您的 XPath 语句中。但是,如果您不想费心将命名空间 URI 放入代码中,则可以只使用该XmlDocument
对象返回根元素的 URI,在这种情况下,这就是您想要的。例如:
XmlDocument xml = new XmlDocument();
xml.Load("sitemap.xml");
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("s", xml.DocumentElement.NamespaceURI); //Using xml's properties instead of hard-coded URI
XmlNodeList xnList = xml.SelectNodes("/s:sitemapindex/s:sitemap", manager);