XPath背后的故事和名称空间的支持是什么? XPath作为规范在命名空间之前吗?如果我有一个文档,其中元素已被赋予默认命名空间:
<foo xmlns="uri" />
似乎某些XPath处理器库由于名称空间而无法识别//foo
,而其他库将会识别。我的团队考虑的选项是使用正则表达式向XPath添加名称空间前缀(可以通过XmlNameTable添加名称空间前缀),但这似乎很脆弱,因为在节点测试时XPath是一种非常灵活的语言。
是否有适用于此的标准?
我的方法有点hackish但似乎工作正常;我使用search / replace删除xmlns
声明,然后应用XPath。
string readyForXpath = Regex.Replace(xmldocument, "xmlns=\".+\"", String.Empty );
这是一种公平的方法还是有人以不同的方式解决了这个问题?
答案 0 :(得分:15)
您需要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
答案 1 :(得分: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
答案 2 :(得分:4)
问题是没有命名空间的元素被声明为在NULL命名空间中 - 因此如果// foo与你认为是'default'的命名空间匹配,那么就无法引用一个元素。 null namespace。
还要记住,命名空间的前缀只是一种简写约定,真实的元素名称(Qualified Name,或简称QName)由完整的命名空间和本地名称组成。更改命名空间的前缀不会更改元素的“标识” - 如果它位于相同的命名空间和相同的本地名称中,则它是相同类型的元素,即使前缀不同。
XPath 2.0(或更确切地说是XSLT 2.0)具有“默认xpath名称空间”的概念。您可以在xsl:stylesheet元素上设置xpath-default-namespace属性。
答案 3 :(得分: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>
或类似的东西。
答案 4 :(得分: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);
}