2012-06-27 44 views
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.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]包含,A00.0,A00.1等節點,而@diags[1]僅包含A00.0內容)。

如何在遍歷get_diags中的xml內容時從父元素中排除嵌套元素?提前致謝!

== ==編輯

所以我將此添加到我的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>被去除,這在某種意義上是我想要,但總體來說這非常非常難看,我想知道是否有人可以分享更好的方式來解決這個問題。謝謝

回答

2

xpath'// diag'會給你每個<diag>節點,反過來,不管嵌套深度如何。然後,你可以提取每個節點的的文本值遞減兒:

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> 
+0

感謝韋恩,代碼的第二位做了我的詭計。 – oort