我有一个 XML 文件需要解析。我无法控制文件的格式,也无法更改它。
该文件使用了一个前缀(称之为a
),但它并未在任何地方为该前缀定义 namespace 。我似乎无法使用 xpath
来查询具有 a
命名空间的节点。
这是xml文件的内容
<?xml version="1.0" encoding="UTF-8"?>
<a:root>
<a:thing>stuff0</a:thing>
<a:thing>stuff1</a:thing>
<a:thing>stuff2</a:thing>
<a:thing>stuff3</a:thing>
<a:thing>stuff4</a:thing>
<a:thing>stuff5</a:thing>
<a:thing>stuff6</a:thing>
<a:thing>stuff7</a:thing>
<a:thing>stuff8</a:thing>
<a:thing>stuff9</a:thing>
</a:root>
我正在使用 Nokogiri 查询文档:
doc = Nokogiri::XML(open('text.xml'))
things = doc.xpath('//a:thing')
失败并给出以下错误:
Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: //a:thing
根据我的研究,我发现我可以在 xpath
方法中为前缀指定 namespace :
things = doc.xpath('//a:thing', a: 'nobody knows')
这将返回一个空数组。
获取所需节点的最佳方式是什么?
最佳答案
问题是命名空间没有在 XML 文档中正确定义。因此,Nokogiri 将节点名称视为“a:root”,而不是将“a”视为 namespace ,将“root”视为节点名称:
xml = %Q{
<?xml version="1.0" encoding="UTF-8"?>
<a:root>
<a:thing>stuff0</a:thing>
<a:thing>stuff1</a:thing>
</a:root>
}
doc = Nokogiri::XML(xml)
puts doc.at_xpath('*').node_name
#=> "a:root"
puts doc.at_xpath('*').namespace
#=> ""
解决方案 1 - 用冒号指定节点名称
一种解决方案是搜索名称为“a:thing”的节点。您不能执行 //a:thing
,因为 XPath 会将“a”视为 namespace 。您可以通过执行 //*[name()="a:thing"]
来解决此问题:
xml = %Q{
<?xml version="1.0" encoding="UTF-8"?>
<a:root>
<a:thing>stuff0</a:thing>
<a:thing>stuff1</a:thing>
</a:root>
}
doc = Nokogiri::XML(xml)
things = doc.xpath('//*[name()="a:thing"]')
puts things
#=> <a:thing>stuff0</a:thing>
#=> <a:thing>stuff1</a:thing>
解决方案 2 - 修改 XML 文档以定义命名空间
另一种解决方案是修改您获得的 XML 文件以正确定义命名空间。然后文档将按预期使用命名空间:
xml = %Q{
<?xml version="1.0" encoding="UTF-8"?>
<a:root>
<a:thing>stuff0</a:thing>
<a:thing>stuff1</a:thing>
</a:root>
}
xml.gsub!('<a:root>', '<a:root xmlns:a="foo">')
doc = Nokogiri::XML(xml)
things = doc.xpath('//a:thing')
puts things
#=> <a:thing>stuff0</a:thing>
#=> <a:thing>stuff1</a:thing>
关于ruby - 如何在有前缀但没有 namespace 的节点上使用 xpath?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20004081/