我正在使用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]
元素,但问题是父节点仍然包含在以后的节点中找到的所有内容(例如A00
包含A00.0
,A00.1
,@diags[1]
等节点,而A00.0
仅包含get_diags
内容。
如何在遍历get_diags
中的xml内容时从父元素中排除嵌套元素?提前谢谢!
==编辑==
所以我将此添加到我的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
现在<diag>...</diag>
拥有xml的片段,其中所有嵌套的{{1}}都被删除了,这在某种意义上就是我想要的,但总的来说这非常非常难看,我想知道是否有人能够分享一个更好的方式来解决这个问题。感谢
答案 0 :(得分: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>