XML命名空间和XPath

Cod*_*der 8 c# xml xpath

我有一个应用程序,必须根据XPath加载XML文档和输出节点.

假设我从这样的文档开始:

<aaa>
  ...[many nodes here]...
  <bbb>text</bbb>
  ...[many nodes here]...
  <bbb>text</bbb>
  ...[many nodes here]...
</aaa>
Run Code Online (Sandbox Code Playgroud)

用XPath //bbb

到目前为止一切都很好.

并且选择doc.SelectNodes("//bbb");返回所需节点的列表.

然后有人<myfancynamespace:foo/>在根标签中上传一个节点和一个额外名称空间的文档,一切都中断了.

为什么?//bbb并没有给出一点该死的myfancynamespace,理论上它应该是好的//myfancynamespace:foo,因为没有歧义,但表达式返回0结果,就是这样.

这种行为有解决方法吗?

我确实有一个文档的命名空间管理器,我将它传递给Xpath查询.但我不知道名称空间和前缀,所以我不能在查询之前添加它们.

在进行任何选择之前,是否必须预先解析文档以填充命名空间管理器?为什么在地球上这样的行为,它只是没有意义.

编辑:

我正在使用: XmlDocumentXmlNamespaceManager

EDIT2:

XmlDocument doc = new XmlDocument();
doc.XmlResolver = null;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
//I wish I could:
//nsmgr.AddNamespace("magic", "http://magicnamespaceuri/
//...
doc.LoadXML(usersuppliedxml);
XmlNodeList nodes = doc.SelectNodes(usersuppliedxpath, nsmgr);//usersuppliedxpath -> "//bbb"

//nodes.Count should be > 0, but with namespaced document they are 0
Run Code Online (Sandbox Code Playgroud)

EDIT3: 找到一篇文章,用一种解决方法描述问题的实际情况,但不是很漂亮的解决方法:http://codeclimber.net.nz/archive/2008/01/09/How-to-query-a-XPath -doc -即,具有-A-的Default.aspx

几乎似乎剥离xmlns是要走的路......

har*_*rpo 13

您错过了XML命名空间的全部内容.

但是,如果您确实需要对将使用未知命名空间的文档执行XPath,并且您真的不关心它,则需要将其删除并重新加载文档.除非您想local-name()在选择器中的每个点使用该函数,否则XPath将无法以与命名空间无关的方式工作.

private XmlDocument StripNamespace(XmlDocument doc)
{
    if (doc.DocumentElement.NamespaceURI.Length > 0)
    {
        doc.DocumentElement.SetAttribute("xmlns", "");
        // must serialize and reload for this to take effect
        XmlDocument newDoc = new XmlDocument();
        newDoc.LoadXml(doc.OuterXml);
        return newDoc;
    }
    else
    {
        return doc;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 重要的是要指出此函数不会删除文档中的所有名称空间; 它显然旨在从最外层元素位于任何命名空间(默认或其他)的文档的最外层元素中删除任何默认命名空间声明.有点奇怪的规范,但如果整个文档在默认命名空间中,并且在文档中没有默认的命名空间声明,那么它将完成您想要的操作. (2认同)

Ali*_*tad 6

<myfancynamespace:foo/>不一定是一样的<foo/>.

命名空间很重要. 但是我可以理解你的挫败感,因为它们通常会打破代码,因为各种实现(C#,Java,...)倾向于以不同的方式输出它.

我建议您更改XPath以允许接受所有名称空间.例如,而不是

//bbb 
Run Code Online (Sandbox Code Playgroud)

将其定义为

//*[local-name()='bbb']
Run Code Online (Sandbox Code Playgroud)

那应该照顾它.

  • 如果用户输入XPath,那么他必须了解名称空间及其含义.这是XML中最不了解的特性,所以我可以看到你可能对用户有一些问题,但让他们知道`local-name()`,他们应该能够快速获取它. (2认同)