XML 到 Ruby Class 的分配出错了

Assignment of XML to Ruby Class gone awry

我正在将 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 旨在保存以下部分的信息:

class Person
  attr_accessor :person 

  def initialize(info)
    @person = info
  end

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

然后是处理消息并将 "persons" 分配给 Person class 并执行进一步处理的代码:

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 总是 "yes"。在 get_lungs 函数中,实际上可以遍历原始消息中的所有值,即使 Person 对象应该只包含消息中的一个人部分。

每个文档节点仍然可以访问整个文档(参见 documentation)。 尽管看起来您只传递了一个 person 节点,但该节点仍然引用了整个文档!

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

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

不依赖于 @person,并且总是 returns 第一个 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"