XML到Ruby类的分配出错了

时间:2017-02-02 17:04:10

标签: ruby xml xpath nokogiri

我将XPath搜索的结果分配给Ruby对象,但该对象似乎可以访问整个原始文档,而不仅仅是我分配的内容。

这是我正在经历的一个简化示例:

<message>
  <person>
    <name>Joe</name>
    <organs>
       <heart>yes</heart>
       <lungs>yes</lungs>
       <ears>yes</ears>
    </organs>
  </person>
  <person>
    <name>Jim</name>
    <organs>
       <heart>yes</heart>
       <lungs>no</lungs>
       <ears>yes</ears>
    </organs>
  </person>
  <person>
    <name>Fred</name>
    <organs>
       <heart>yes</heart>
       <lungs>maybe</lungs>
       <ears>yes</ears>
    </organs>
  </person>
</message>

然后我有一个专门用于保存部分信息的课程:

class Person
  attr_accessor :person 

  def initialize(info)
    @person = info
  end

  def get_lungs
    return @person.xpath("//organs/lungs").first.content
  end
end

然后是处理消息并将“人员”分配给Person类并执行进一步处理的代码:

message = doc.xpath("message")
message.xpath('person').each do |p|
  prsn = Person.new(p)
  queue.push("person" => prsn)  
end

loop ...
  work - queue.pop
  per = work['person']
  lungs = per.get_lungs  
end

问题是,lungs总是“是”。在get_lungs函数中,实际上可以循环遍历原始消息中的所有值,即使Person对象应该只包含消息中的一个人部分。

1 个答案:

答案 0 :(得分:1)

每个文档节点仍然可以访问整个文档(请参阅documentation)。 即使您只是传递person节点,该节点仍然引用整个文档!

另外,// scans the whole document,所以

@person.xpath("//organs/lungs").first

不依赖@person并始终返回第一个lung。您也可以使用at_xpath代替xpath.first

只需删除//即可:

require 'nokogiri'

doc = Nokogiri::XML(message)

doc.xpath('//person').each do |person|
  p person.at_xpath("organs/lungs").content
end

输出:

"yes"
"no"
"maybe"