XPATHS和默认命名空间

时间:2020-03-05 18:39:41  来源:igfitidea点击:

XPath和对名称空间的支持背后的故事是什么? XPath作为规范是否先于名称空间?如果我有一个文档,其中元素已被赋予默认名称空间:

<foo xmlns="uri" />

似乎某些XPath处理器库由于名称空间而无法识别// foo,而其他则可以。我的团队考虑过的选项是使用正则表达式向XPath添加名称空间前缀(我们可以通过XmlNameTable添加名称空间前缀),但这似乎很脆弱,因为XPath在节点测试方面是一种灵活的语言。

是否有适用于此的标准?

我的方法有点骇人听闻,但似乎很好用。我用搜索/替换删除了xmlns声明,然后应用了XPath。

string readyForXpath = Regex.Replace(xmldocument, "xmlns=\".+\"", String.Empty );

这是一个公平的方法还是有人解决了这个问题?

解决方案

回答

我们需要local-name():

http://www.w3.org/TR/xpath#function-local-name

要从http://jcooney.net/archive/2005/08/09/6517.aspx婴儿床:

<foo xmlns='urn:foo'>
  <bar>
    <asdf/>
  </bar>            
</foo>

此表达式将匹配bar元素:

//*[local-name()='bar']

这不会:

//bar

回答

如果我们尝试使用xslt,则可以将名称空间添加到样式表声明中。如果这样做,则必须确保有前缀,否则前缀将不起作用。如果源XML没有前缀,那还是可以的,我们可以在样式表中添加自己的前缀。

样式表

<xsl:stylesheet
    xmlns:fb="uri"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="fb:foo/bar">
        <!--  do stuff here -->
    </xsl:template>
</xsl:stylsheet>

或者类似的东西。

回答

问题在于,没有命名空间的元素被声明为NULL命名空间,因此,如果// foo与我们认为是"默认"的命名空间匹配,将无法在null命名空间中引用元素。

还要记住,名称空间的前缀只是一种速记约定,真实元素名称(Qualified Name,简称QName)由完整的名称空间和本地名称组成。更改名称空间的前缀不会更改元素的"身份",即使该元素在相同的名称空间和相同的本地名称中也意味着该元素是同一类型的元素,即使前缀不同。

XPath 2.0(或者XSLT 2.0)具有"默认xpath名称空间"的概念。我们可以在xsl:stylesheet元素上设置xpath-default-namespace属性。

回答

我尝试了与古马提议的类似的方法,但无法使其正常工作。由于我从发布的服务中获取数据,因此无法更改xml。我最终像这样使用XmlDocument和XmlNamespaceManager:

XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlWithBogusNamespace);            
XmlNamespaceManager nSpace = new XmlNamespaceManager(doc.NameTable);
nSpace.AddNamespace("myNs", "http://theirUri");

XmlNodeList nodes = doc.SelectNodes("//myNs:NodesIWant",nSpace);
//etc