XPath和对名称空间的支持背后的故事是什么? XPath作为规范是否先于名称空间? 如果我有一个文档,其中元素已被赋予默认名称空间:
似乎某些XPath处理器库由于名称空间而无法识别//foo,而其他XPath处理器库则无法识别。 我的团队考虑过的选项是使用正则表达式向XPath添加名称空间前缀(您可以通过XmlNameTable添加名称空间前缀),但这似乎很脆弱,因为XPath在涉及节点测试时是一种灵活的语言。
是否有适用于此的标准?
我的方法有点骇人听闻,但似乎效果很好。 我用搜索/替换删除了xmlns声明,然后应用XPath。
1
| string readyForXpath = Regex.Replace(xmldocument,"xmlns=".+"", String.Empty ); |
这是一个公平的方法还是有人解决了这个问题?
您需要local-name():
http://www.w3.org/TR/xpath#function-local-name
要从http://jcooney.net/archive/2005/08/09/6517.aspx婴儿床:
1 2 3 4 5
| <foo xmlns='urn:foo'>
<bar>
</bar>
</foo> |
此表达式将匹配" bar"元素:
1
| //*[local-name()='bar'] |
这不会:
我尝试了与古马提议的类似的方法,但无法使其正常工作。由于我从发布的服务中获取数据,因此无法更改xml。我最终像这样使用XmlDocument和XmlNamespaceManager:
1 2 3 4 5 6 7
| 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 |
问题在于,没有命名空间的元素被声明为NULL命名空间-因此,如果// foo与命名空间匹配,则您认为这是"默认",将无法在null命名空间中引用元素。
还要记住,名称空间的前缀只是一种速记约定,真实元素名称(Qualified Name,简称QName)由完整的名称空间和本地名称组成。更改名称空间的前缀不会更改元素的"身份"-如果元素位于相同的名称空间和相同的本地名称中,则即使元素前缀不同,它也属于相同类型的元素。
XPath 2.0(或XSLT 2.0)具有"默认xpath名称空间"的概念。您可以在xsl:stylesheet元素上设置xpath-default-namespace属性。
使用libxml似乎可行:
http://xmlsoft.org/examples/xpath1.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| 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) == '\0') break;
/* find prefix */
prefix = next;
next = (xmlChar*)xmlStrchr(next, '=');
if(next == NULL) {
fprintf(stderr,"Error: invalid namespaces list format
");
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"
", prefix, href);
xmlFree(nsListDup);
return(-1);
}
}
xmlFree(nsListDup);
return(0);
} |
如果您尝试使用xslt,则可以将名称空间添加到样式表声明中。如果这样做,则必须确保有前缀,否则前缀将不起作用。如果源XML没有前缀,那还是可以的,您可以在样式表中添加自己的前缀。
样式表
1 2 3 4 5 6 7 8
| <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> |
或类似的东西。