0

我正在使用 Nokogiri 解析具有(大致)以下结构的 XML 文件:

<diag>
  <name>A00</name>
  <desc>Cholera</desc>
  <diag>
    <name>A00.0</name>
    <desc>Cholera due to Vibrio cholerae 01, biovar cholerae</desc>
  </diag>
  <diag>
    ...
  </diag>
  ...
</diag>

正如你所看到的,这棵树有diag可以任意嵌套深度的节点,但是每个嵌套都是对父节点的更具体的描述。

我想“展平”这棵树,这样我就可以拥有一个类似的列表,而不是A00.0嵌套在其中A00

A00
A00.0
A00.1
...
A00.34
...
A01
...

我到目前为止看起来像这样:

require 'nokogiri'
icd10 = File.new("icd10.xml", "r")
doc = Nokogiri::XML(icd10.read) do |config|
  config.strict.noblanks
end
icd10.close

@diags = {}
@diag_count = 0

def get_diags(node)
  node.children.each do |n|
    if n.name == "diag"
      @diags[@diag_count] = n
      @diag_count += 1
      get_diags(n)
    end
  end
end

# The xml file has sections but what I really want are the contents of the sections
doc.xpath('.//section').each do |n|
  get_diags(n)
end

到目前为止,这有效,因为我确实获得diag了文件中的所有元素,但问题是父节点仍然包含在以后节点中找到的所有内容(例如,@diags[0]包含A00A00.0A00.1等节点,而@diags[1]仅包含A00.0内容)。

如何在遍历 xml 内容时从父元素中排除嵌套元素get_diags?提前致谢!

== 编辑 ==

所以我将此添加到我的get_diags方法中

def get_diags(node)
  node.children.each do |n|
    if n.name == "diag"
      f = Nokogiri::XML.fragment(n.to_s)
      f.search('.//diag').children.each do |d|
        if d.name == "diag"
          d.remove
        end
      end
      @diags[@diag_count] = f
      @diag_count += 1
      get_diags(n)
    end
  end
end

现在@diags拥有一个 xml 片段,其中所有嵌套<diag>...</diag>都被删除,从某种意义上说,这是我想要的,但总的来说这非常难看,我想知道是否有人可以分享一个更好的方法来解决这个问题。谢谢

4

1 回答 1

2

xpath '//diag' 将<diag>依次为您提供每个节点,无论嵌套多深。然后您可以提取每个节点名称desc子节点的文本值:

diags = doc.xpath('//diag').map do |diag|
  Hash[
    %w(name desc).map do |key|
      [key, diag.xpath(key).text]
    end
  ]
end
pp diags
# => [{"desc"=>"Cholera", "name"=>"A00"},
# =>  {"desc"=>"Cholera due to Vibrio cholerae 01, biovar cholerae",
# =>   "name"=>"A00.0"}]

如果您希望创建具有不同结构的新 XML 树,我不会费心尝试转换原始树。只需提取提取的数据并使用它来创建新树:

builder = Nokogiri::XML::Builder.new do |xml|
  xml.diagnoses do
  diags.each do |diag|
    xml.diag {
      xml.name = diag['name']
      xml.desc = diag['desc']
    }
  end
  end
end
puts builder.to_xml
# => <?xml version="1.0"?>
# => <diagnoses>
# =>   <diag>
# =>     <name=>A00</name=>
# =>     <desc=>Cholera</desc=>
# =>   </diag>
# =>   <diag>
# =>     <name=>A00.0</name=>
# =>     <desc=>Cholera due to Vibrio cholerae 01, biovar cholerae</desc=>
# =>   </diag>
# => </diagnoses>
于 2012-06-27T17:29:13.263 回答