XPATHS 和默认命名空间
Posted
技术标签:
【中文标题】XPATHS 和默认命名空间【英文标题】:XPATHS and Default Namespaces 【发布时间】:2010-09-05 21:31:07 【问题描述】:XPath 背后的故事和对命名空间的支持是什么? XPath 作为规范是否先于命名空间?如果我有一个文档,其中元素被赋予了默认命名空间:
<foo xmlns="uri" />
似乎有些 XPath 处理器库由于命名空间的原因无法识别 //foo
,而其他的则可以。我的团队考虑的选项是使用正则表达式向 XPath 添加命名空间前缀(您可以通过 XmlNameTable 添加命名空间前缀),但这似乎很脆弱,因为在节点测试方面 XPath 是一种非常灵活的语言。
是否有适用于此的标准?
我的方法有点老套,但似乎效果很好;我使用搜索/替换删除xmlns
声明,然后应用XPath。
string readyForXpath = Regex.Replace(xmldocument, "xmlns=\".+\"", String.Empty );
这是一种公平的方法还是有人以不同的方式解决了这个问题?
【问题讨论】:
【参考方案1】:你需要local-name():
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
【讨论】:
如果您的文档有另一个来自不同命名空间的bar
,那么您的解决方案将同时选择两者。
正确,但我认为这仍然比像 OP 计划那样正则表达式命名空间要好。【参考方案2】:
我尝试了类似于 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
【讨论】:
如果你想选择使用多个深度的节点,你最终不得不这样做:xml.SelectNodes("kml:kml/kml:Document/kml:Folder", manager)
【参考方案3】:
问题在于,没有命名空间的元素被声明为在 NULL 命名空间中 - 因此,如果 //foo 与您认为是“默认”的命名空间匹配,则无法引用空命名空间。
还要记住,命名空间的前缀只是一个简写约定,真正的元素名称(Qualified Name,简称 QName)由完整的命名空间和本地名称组成。更改命名空间的前缀不会改变元素的“身份”——如果它在同一个命名空间和相同的本地名称中,那么它就是同一种元素,即使前缀不同。
XPath 2.0(或者更确切地说是 XSLT 2.0)具有“默认 xpath 命名空间”的概念。您可以在 xsl:stylesheet 元素上设置 xpath-default-namespace 属性。
【讨论】:
【参考方案4】:如果您尝试使用 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>
或者类似的东西。
【讨论】:
【参考方案5】:使用 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);
【讨论】:
以上是关于XPATHS 和默认命名空间的主要内容,如果未能解决你的问题,请参考以下文章
具有显式默认命名空间的 XML 文档的 XPath 和命名空间规范
Hadoop—如何查看HDFS默认的ns命名空间和所有命名空间列表