C# XPATHS 和默认命名空间

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-07-31 17:38:47  来源:igfitidea点击:

XPATHS and Default Namespaces

提问by t3rse

What is the story behind XPath and support for namespaces? Did XPath as a specification precede namespaces? If I have a document where elements have been given a default namespace:

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

<foo xmlns="uri" />

It appears as though some of the XPath processor libraries won't recognize //foobecause of the namespace whereas others will. The option my team has thought about is to add a namespace prefix using regular expressions to the XPath (you can add a namespace prefix via XmlNameTable) but this seems brittle since XPath is such a flexible language when it comes to node tests.

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

Is there a standard that applies to this?

是否有适用于此的标准?

My approach is a bit hackish but it seems to work fine; I remove the xmlnsdeclaration with a search/replace and then apply XPath.

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

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

Is that a fair approach or has anyone solved this differently?

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

采纳答案by Andrew Cowenhoven

I tried something similar to what palehorse proposed and could not get it to work. Since I was getting data from a published service I couldn't change the xml. I ended up using XmlDocument and XmlNamespaceManager like so:

我尝试了类似于 Palehorse 提出的方法,但无法使其正常工作。由于我从已发布的服务中获取数据,因此无法更改 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

回答by Stu

You need local-name():

您需要本地名称():

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

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

To crib from http://jcooney.net/archive/2005/08/09/6517.aspx:

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

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

This expression will match the “bar” element:

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

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

This one won't:

这个不会:

 //bar

回答by palehorse

If you are trying to use xslt you can add the namespace in to the stylesheet declaration. If you do that, you must make sure that there is a prefix or it will not work. If the source XML does not have a prefix, that is still fine, you add your own prefix in the stylesheet.

如果您尝试使用 xslt,您可以将命名空间添加到样式表声明中。如果你这样做,你必须确保有一个前缀,否则它将不起作用。如果源 XML 没有前缀,那仍然可以,您可以在样式表中添加自己的前缀。

Stylesheet

样式表

<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>

Or something like that.

或类似的东西。

回答by samjudson

The issue is that an element without a namespace is declared to be in the NULL namespace - therefore if //foo matched against the namespace you consider to be the 'default' there would be no way to refer to an element in the null namespace.

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

Remember as well that the prefix for a namespace is only a shorthand convention, the real element name (Qualified Name, or QName for short) consists of the full namespace and the local name. Changing the prefix for a namespace does not change the 'identity' of an element - if it is in the same namespace and same local name then it is the same kind of element, even if the prefix is different.

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

XPath 2.0 (or rather XSLT 2.0) has the concept of the 'default xpath namespace'. You can set the xpath-default-namespace attribute on the xsl:stylesheet element.

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

回答by crazy dev

Using libxml it seems this works:

使用 libxml 似乎这有效:

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

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) == '##代码##') 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++) = '##代码##';   

    /* 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\"\n", prefix, href);
        xmlFree(nsListDup);
        return(-1); 
    }
    }

    xmlFree(nsListDup);
    return(0);
}