XPATHS和默认命名空间

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XPATHS和默认命名空间相关的知识,希望对你有一定的参考价值。

XPath背后的故事是什么以及对名称空间的支持? XPath作为规范在命名空间之前吗?如果我有一个文档,其中元素已被赋予默认命名空间:

<foo xmlns="uri" />

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

是否有适用于此的标准?

我的方法有点hackish但似乎工作正常;我用搜索/替换删除xmlns声明然后应用XPath。

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

这是一种公平的方法还是有人以不同方式解决了这个问

答案

我尝试了类似于古代建议的东西,无法让它发挥作用。由于我从已发布的服务获取数据,因此无法更改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
另一答案

你需要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
另一答案

问题是没有命名空间的元素被声明为在NULL命名空间中 - 因此如果// foo与您认为是'default'的命名空间匹配,则无法引用null命名空间中的元素。

还要记住,命名空间的前缀只是一种简写约定,真实的元素名称(Qualified Name,或简称QName)由完整的命名空间和本地名称组成。更改命名空间的前缀不会更改元素的“标识” - 如果它位于相同的命名空间和相同的本地名称中,则它是相同类型的元素,即使前缀不同也是如此。

XPath 2.0(或更确切地说是XSLT 2.0)具有“默认xpath命名空间”的概念。您可以在xsl:stylesheet元素上设置xpath-default-namespace属性。

另一答案

如果您尝试使用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>

或类似的东西。

另一答案

使用libxml似乎这是有效的:

http://xmlsoft.org/examples/xpath1.c

 int 
register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList) {
    xmlChar* nsListDup;
    xmlChar* prefix;
    xmlChar* href;
    xmlChar* next;

    assert(xpathCtx);
    assert(nsList);

    nsListDup = xmlStrdup(nsList);
    if(nsListDup == NULL) {
    fprintf(stderr, "Error: unable to strdup namespaces list
");
    return(-1); 
    }

    next = nsListDup; 
    while(next != NULL) {
    /* skip spaces */
    while((*next) == ' ') next++;
    if((*next) == '') break;

    /* find prefix */
    prefix = next;
    next = (xmlChar*)xmlStrchr(next, '=');
    if(next == NULL) {
        fprintf(stderr,"Error: invalid namespaces list format
");
        xmlFree(nsListDup);
        return(-1); 
    }
    *(next++) = '';   

    /* find href */
    href = next;
    next = (xmlChar*)xmlStrchr(next, ' ');
    if(next != NULL) {
        *(next++) = '';   
    }

    /* do register namespace */
    if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) {
        fprintf(stderr,"Error: unable to register NS with prefix="%s" and href="%s"
", prefix, href);
        xmlFree(nsListDup);
        return(-1); 
    }
    }

    xmlFree(nsListDup);
    return(0);
}

以上是关于XPATHS和默认命名空间的主要内容,如果未能解决你的问题,请参考以下文章

VSCODE 片段 PHP 自动填充命名空间

xml 中的 Android 谷歌地图片段。我得到“意外的命名空间前缀”

如何在C ++中将枚举导入不同的命名空间?

命名空间

G++ 和 Clang++ - 命名空间标准 _GLIBCXX_VISIBILITY(默认)

XSD:命名空间和默认命名空间有啥区别