Использование Nokogiri с файлами XML в Ruby - PullRequest
0 голосов
/ 09 июля 2010

У меня есть этот 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 -> accession (D017209 и D019014).Что мне нужно изменить в команде doc.xpath, чтобы это работало?

Ответы [ 2 ]

2 голосов
/ 09 июля 2010
doc.xpath( "/ExperimentCollection/Experiment/mzData/description/admin/sampleDescription/MeSH/@accession" )

Ничего не возвращает, потому что нет тега MeSH. Вам необходимо заменить MeSH на cvParam[@cvLabel=\"MeSH\"] (читай: тег cvParam, который имеет атрибут cvLabel со значением MeSH).

Как только вы исправите это, xpath вернет коллекцию Nokogiri::XML::Attr объектов. Вызвав текст этой коллекции, вы получите строковое значение первого элемента. Поскольку вам нужны все элементы, вы должны вместо этого использовать map(&:text) (или map {|n| n.text} в ruby ​​1.8.6), который будет возвращать массив, содержащий строковое значение каждого атрибута accession (то есть ["D017209", "D019014"] для примера XML- файл).

Так как вы, кажется, смущены, вот пояснение:

@ Бобби: Когда я сказал "xpath вернет коллекцию Nokogiri::XML::Attr объектов", я имел в виду именно это. Вы вызываете xpath, а затем xpath создает и возвращает коллекцию Attr объектов. Я никоим образом не имел в виду, что вы должны вручную создавать любые Attr объекты.

И когда я сказал, что вы должны использовать map, я просто имел в виду, что вы должны вызвать map для коллекции, возвращаемой xpath (хотя вместо использования map вы можете просто вызвать puts с коллекцией как аргумент).

  1. Итак, вам нужно 1. исправить ваш xpath, как я описал.
  2. используйте xpath с фиксированным xpath для получения коллекции
  3. использует путы, чтобы распечатать его

Другими словами:

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
0 голосов
/ 16 июля 2010

Вот простой способ сделать это, хотя это, вероятно, слишком умно, потому что вы, вероятно, захотите сделать и другие вещи:

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

Возможно, вам понадобится более избирательный оператор xpath.

...