16

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

<foo xmlns="uri" />

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

有适用于此的标准吗?

我的方法有点老套,但似乎效果很好;我使用搜索/替换删除xmlns声明,然后应用 XPath。

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

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

4

5 回答 5

15

您需要本地名称():

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

http://web.archive.org/web/20100810142303/http://jcooney.net:80/archive/2005/08/09/6517.aspx到婴儿床:

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

此表达式将匹配“bar”元素:

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

这个不会:

 //bar
于 2008-08-14T17:15:17.927 回答
10

我尝试了类似于白马提议的方法,但无法使其正常工作。由于我从已发布的服务中获取数据,因此无法更改 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
于 2008-09-29T15:09:35.493 回答
4

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

还要记住,命名空间的前缀只是一个简写约定,真正的元素名称(Qualified Name,简称 QName)由完整的命名空间和本地名称组成。更改命名空间的前缀不会改变元素的“身份”——如果它位于相同的命名空间和相同的本地名称中,那么即使前缀不同,它也是同一种元素。

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

于 2008-08-19T14:38:33.190 回答
0

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

或类似的东西。

于 2008-08-14T17:22:27.943 回答
0

使用 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\n");
    return(-1); 
    }

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

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

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

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

    xmlFree(nsListDup);
    return(0);
}
于 2018-03-01T07:07:42.003 回答