我有XML,我正在尝试使用Nokogiri解析并获取每个心跳测试的状态。
这是我的代码:
xml =
<a:HBeat>
<a:ElapsedTime>3 ms</a:ElapsedTime>
<a:Name>Service 1</a:Name>
<a:Status>true</a:Status>
</a:HBeat>
<a:HBeat>
<a:ElapsedTime>4 ms</a:ElapsedTime>
<a:Name>Service 2</a:Name>
<a:Status>true</a:Status>
</a:HBeat>
<a:HBeat>
我已经尝试同时使用css
和xpath
来检索每个Status的值并将其放入数组:
doc = Nokogiri::XML.parse(xml)
#service_state = doc.css("a:HBeat, a:Status", 'a' => 'http://schemas.datacontract.org/2004/07/OpenAPI.Entity').map {|node| node.children.text}
service_state = doc.xpath("//*[@a:Status]", 'a' => 'http://schemas.datacontract.org/2004/07/OpenAPI.Entity').map(&:text)
两者都将返回service_state = []
我在另一项测试中使用的XML几乎相同,并且我使用了以下代码片段,这些代码完全符合我的要求,但由于某些原因,它们不能用于包含名称空间的XML:
service_state = doc.css("HBeat Status").map(&:text)
除了Greg的响应(XML需要一个包含元素)之外,您的XPath表达式选择了错误的内容:
//*[@a:Status]
选择具有a:Status
属性的所有元素。如果要所有具有子a:Status
元素的元素,只需从节点测试中删除@
:
//*[a:Status]
部分问题是您的XML示例不正确:尽管您使用的是名称空间,但是缺少名称空间声明,并且您缺少包含标签。第一个可以解决,但是第二个需要对XML进行调整。
require 'nokogiri'
require 'pp'
xml = <<EOT
<xml xmlns:a="http://schemas.datacontract.org/2004/07/OpenAPI.Entity"> # <-- changed
<a:HBeat>
<a:ElapsedTime>3 ms</a:ElapsedTime>
<a:Name>Service 1</a:Name>
<a:Status>true</a:Status>
</a:HBeat>
<a:HBeat>
<a:ElapsedTime>4 ms</a:ElapsedTime>
<a:Name>Service 2</a:Name>
<a:Status>true</a:Status>
</a:HBeat>
<a:HBeat>
</xml>
EOT
doc = Nokogiri::XML(xml)
service_state = doc.css('a|Status').map(&:text) # <-- changed to show CSS with namespace
pp service_state
service_state = doc.search('//a:Status').map(&:text) # <-- added
pp service_state # <-- added
>> ruby test.rb
>> ["true", "true"]
>> ["true", "true"] # <-- added
命名空间是一件好事,但是当您只想获取数据时,处理它们可能会很痛苦。 Nokogiri有一些使它们不那么烦人的技巧,例如像我上面那样使用CSS访问器,这意味着“在所有名称空间中找到Status标记”,因此即使未声明名称空间也还是不错的。
如果您控制XML,则可以删除名称空间。当处理可能的标签冲突时,它们很棒,但是当您拥有生成文件的机制时,这不太可能,因此,如果是这样,您可以取消它们。如果需要命名空间,则应将其声明为以下形式:
<xml xmlns:a="http://schemas.datacontract.org/2004/07/OpenAPI.Entity">
没有它,XML解析出很多名称空间错误:
(rdb:1) pp doc.errors
[#<Nokogiri::XML::SyntaxError: Namespace prefix a on HBeat is not defined>,
#<Nokogiri::XML::SyntaxError: Namespace prefix a on ElapsedTime is not defined>,
#<Nokogiri::XML::SyntaxError: Namespace prefix a on Name is not defined>,
#<Nokogiri::XML::SyntaxError: Namespace prefix a on Status is not defined>,
#<Nokogiri::XML::SyntaxError: Namespace prefix a on HBeat is not defined>,
#<Nokogiri::XML::SyntaxError: Namespace prefix a on ElapsedTime is not defined>,
#<Nokogiri::XML::SyntaxError: Namespace prefix a on Name is not defined>,
#<Nokogiri::XML::SyntaxError: Namespace prefix a on Status is not defined>,
#<Nokogiri::XML::SyntaxError: Namespace prefix a on HBeat is not defined>,
#<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: HBeat line 12 and xml>,
#<Nokogiri::XML::SyntaxError: Premature end of data in tag xml line 1>]
但是将其添加后,文档的错误列表要小得多:
(rdb:1) pp doc.errors
[#<Nokogiri::XML::SyntaxError: Opening and ending tag mismatch: HBeat line 12 and xml>,
#<Nokogiri::XML::SyntaxError: Premature end of data in tag xml line 1>]
另请参见“ How to avoid joining all text from Nodes when scraping”。