我正在努力寻找正确的XPath表达式和命名空间规范的组合,如
一旦查询命名空间,
所以我们只需指定一个作为前缀的名称(这可以是任何有效的R名称):
现在我们只需要在XPath表达式中任何地方使用默认的命名空间前缀即可:
这似乎让我更接近了:
XML
包(参数 namespaces
)所需,适用于具有在顶级元素中定义了显式 xmlns
命名空间的 XML 文档。
更新
感谢 har07 的帮助,我终于把它整理好了。一旦查询命名空间,
ns
的第一个条目尚未命名,这就是问题所在:nsDefs <- xmlNamespaceDefinitions(doc)
ns <- structure(sapply(nsDefs, function(x) x$uri), names = names(nsDefs))
> ns
omegahat r
"http://something.org" "http://www.omegahat.org" "http://www.r-project.org"
所以我们只需指定一个作为前缀的名称(这可以是任何有效的R名称):
names(ns)[1] <- "xmlns"
现在我们只需要在XPath表达式中任何地方使用默认的命名空间前缀即可:
getNodeSet(doc, "/xmlns:doc//xmlns:b[@omegahat:status='foo']", ns)
对于那些希望基于 name()
和 namespace-uri()
(等等)的替代方案的人可能会发现这篇文章有所帮助。
仅供参考:在我们找到解决方案之前,这是试错代码:
考虑来自?xmlParse
的示例:
require("XML")
doc <- xmlParse(system.file("exampleData", "tagnames.xml", package = "XML"))
> doc
<?xml version="1.0"?>
<doc>
<!-- A comment -->
<a xmlns:omegahat="http://www.omegahat.org" xmlns:r="http://www.r-project.org">
<b>
<c>
<b/>
</c>
</b>
<b omegahat:status="foo">
<r:d>
<a status="xyz"/>
<a/>
<a status="1"/>
</r:d>
</b>
</a>
</doc>
nsDefs <- xmlNamespaceDefinitions(getNodeSet(doc, "/doc/a")[[1]])
ns <- structure(sapply(nsDefs, function(x) x$uri), names = names(nsDefs))
getNodeSet(doc, "/doc//b[@omegahat:status='foo']", ns)[[1]]
然而,在我的文档中,命名空间已经在<doc>
标签中定义了,因此我相应地调整了示例XML代码:
xml_source <- c(
"<?xml version=\"1.0\"?>",
"<doc xmlns:omegahat=\"http://www.omegahat.org\" xmlns:r=\"http://www.r-project.org\">",
"<!-- A comment -->",
"<a>",
"<b>",
"<c>",
"<b/>",
"</c>",
"</b>",
"<b omegahat:status=\"foo\">",
"<r:d>",
"<a status=\"xyz\"/>",
"<a/>",
"<a status=\"1\"/>",
"</r:d>",
"</b>",
"</a>",
"</doc>"
)
write(xml_source, file="exampleData_2.xml")
doc <- xmlParse("exampleData_2.xml")
nsDefs <- xmlNamespaceDefinitions(doc)
ns <- structure(sapply(nsDefs, function(x) x$uri), names = names(nsDefs))
getNodeSet(doc, "/doc", namespaces = ns)
getNodeSet(doc, "/doc//b[@omegahat:status='foo']", namespaces = ns)[[1]]
一切仍然正常。更重要的是,我的XML代码还具有默认命名空间的明确定义(xmlns
):
xml_source <- c(
"<?xml version=\"1.0\"?>",
"<doc xmlns=\"http://something.org\" xmlns:omegahat=\"http://www.omegahat.org\" xmlns:r=\"http://www.r-project.org\">",
"<!-- A comment -->",
"<a>",
"<b>",
"<c>",
"<b/>",
"</c>",
"</b>",
"<b omegahat:status=\"foo\">",
"<r:d>",
"<a status=\"xyz\"/>",
"<a/>",
"<a status=\"1\"/>",
"</r:d>",
"</b>",
"</a>",
"</doc>"
)
write(xml_source, file="exampleData_3.xml")
doc <- xmlParse("exampleData_3.xml")
nsDefs <- xmlNamespaceDefinitions(doc)
ns <- structure(sapply(nsDefs, function(x) x$uri), names = names(nsDefs))
曾经有效的方法现在已经失效:
> getNodeSet(doc, "/doc", namespaces = ns)
list()
attr(,"class")
[1] "XMLNodeSet"
Warning message:
using http://something.org as prefix for default namespace http://something.org
> getNodeSet(doc, "/xmlns:doc", namespaces = ns)
XPath error : Undefined namespace prefix
XPath error : Invalid expression
Error in xpathApply.XMLInternalDocument(doc, path, fun, ..., namespaces = namespaces, :
error evaluating xpath expression /xmlns:doc
In addition: Warning message:
using http://something.org as prefix for default namespace http://something.org
getNodeSet(doc, "/xmlns:doc",
namespaces = matchNamespaces(doc, namespaces="xmlns", nsDefs = nsDefs)
)
这似乎让我更接近了:
> getNodeSet(doc, "/xmlns:doc",
+ namespaces = matchNamespaces(doc, namespaces="xmlns", nsDefs = nsDefs)
+ )[[1]]
<doc xmlns="http://something.org" xmlns:omegahat="http://www.omegahat.org" xmlns:r="http://www.r-project.org">
<!-- A comment -->
<a>
<b>
<c>
<b/>
</c>
</b>
<b omegahat:status="foo">
<r:d>
<a status="xyz"/>
<a/>
<a status="1"/>
</r:d>
</b>
</a>
</doc>
attr(,"class")
[1] "XMLNodeSet"
但是,我现在不知道如何继续以便获取子节点:
> getNodeSet(doc, "/xmlns:doc//b[@omegahat:status='foo']", ns)[[1]]
XPath error : Undefined namespace prefix
XPath error : Invalid expression
Error in xpathApply.XMLInternalDocument(doc, path, fun, ..., namespaces = namespaces, :
error evaluating xpath expression /xmlns:doc//b[@omegahat:status='foo']
In addition: Warning message:
using http://something.org as prefix for default namespace http://something.org
> getNodeSet(doc, "/xmlns:doc//b[@omegahat:status='foo']",
+ namespaces = c(
+ matchNamespaces(doc, namespaces="xmlns", nsDefs = nsDefs),
+ matchNamespaces(doc, namespaces="omegahat", nsDefs = nsDefs)
+ )
+ )
list()
attr(,"class")
[1] "XMLNodeSet"
ns
是 R 中的自然样条函数。这将覆盖该基本函数。 - Ashe