在Ruby中使用Nokogiri和XML文件

时间:2010-07-09 18:22:52

标签: ruby xml xpath nokogiri

我有这个XML:

<Experiment>
<mzData version="1.05" accessionNumber="1635">
<description>
<admin>
<sampleName>Fas-induced and control Jurkat T-lymphocytes</sampleName> 
<sampleDescription>
<cvParam cvLabel="MeSH" accession="D017209" name="apoptosis" /> 
<cvParam cvLabel="UNITY" accession="D2135" name="Jurkat cells" /> 
<cvParam cvLabel="MeSH" accession="D019014" name="Antigens, CD95" /> 
</sampleDescription>
</admin>
</description>
</mzData>
</Experiment>
</ExperimentCollection>

我还有以下代码:

require 'rubygems'
require 'nokogiri'

doc = Nokogiri::XML(File.open("my.xml"))

sampleName = doc.xpath( "/ExperimentCollection/Experiment/mzData/description/admin/sampleName" ).text
sampleDescription = doc.xpath( "/ExperimentCollection/Experiment/mzData/description/admin/sampleDescription/MeSH/@accession" ).text
puts sampleName + " " + sampleDescription

foo = sampleName + " " + sampleDescription 
f = File.new("my.txt","w")
f.write(foo) 
f.close()

代码抓住sampleName就好了,但不是accession字母/数字。我只想抓住MeSH - &gt;之后的所有字母/数字。 accessionD017209D019014)。我需要在doc.xpath命令中进行哪些更改才能使其正常工作?

2 个答案:

答案 0 :(得分:2)

doc.xpath( "/ExperimentCollection/Experiment/mzData/description/admin/sampleDescription/MeSH/@accession" )

不返回任何内容,因为没有标记MeSH。您需要将MeSH替换为cvParam[@cvLabel=\"MeSH\"](读取:cvParam标记,其属性cvLabel的值为MeSH。)

修复后,xpath将返回Nokogiri::XML::Attr个对象的集合。通过调用该集合上的文本,您将获得第一个元素的字符串值。既然你想要所有的元素,你应该使用map(&:text)(或ruby 1.8.6中的map {|n| n.text}),这将返回一个包含每个accession属性的字符串值的数组(即{{ 1}}用于示例XML文件。)

既然你似乎感到困惑,这里有一个澄清:

@Bobby:当我说“["D017209", "D019014"]将返回xpath个对象的集合”时,我的意思就是这样。您调用Nokogiri::XML::Attr然后xpath创建并返回xpath个对象的集合。我绝不意味着您应该自己手动创建任何Attr个对象。

当我说你应该使用Attr时,我的意思是你应该在map返回的集合上调用map(尽管你可以只使用xpath而不是map以集合作为参数调用puts

  1. 所以你需要做的是1.像我描述的那样修复你的xpath。
  2. 使用xpath和固定的xpath来获取集合
  3. 使用puts来打印
  4. 换句话说:

    require 'rubygems'
    require 'nokogiri'
    
    doc = Nokogiri::XML(File.open("my.xml"))
    
    common_prefix = "/ExperimentCollection/Experiment/mzData/description/admin"
    sample_name = doc.xpath( common_prefix+"/sampleName" ).text
    accessions = doc.xpath( common_prefix+
                   "/sampleDescription/cvParam[@cvLabel=\"MeSH\"]/@accession" )
    
    puts sample_name
    puts accessions
    

答案 1 :(得分:0)

这是一种简单的方法,虽然这可能太聪明了,因为你可能也想做其他事情:

File.open("my.txt","w") do |f|
  doc.xpath('//cvParam[@cvLabel="MeSH"]').each {|n| f << "#{n['name']} #{n['accession']}\n"}
end

您可能需要更具选择性的xpath语句。