2013-08-10 13 views
6

ho questo xml:Nokogiri ogni nodo fare, Ruby

<kapitel> 
     <nummer V="1"/> 
     <von_icd_code V="A00"/> 
     <bis_icd_code V="B99"/> 
     <bezeichnung V="Bestimmte infektiöse und parasitäre Krankheiten"/> 
     <gruppen_liste> 
     <gruppe> 
      <von_icd_code V="A00"/> 
      <bis_icd_code V="A09"/> 
      <bezeichnung V="Infektiöse Darmkrankheiten"/> 
      <diagnosen_liste> 
      <diagnose> 
       <icd_code V="A00.-"/> 
       <bezeichnung V="Cholera"/> 
       <abrechenbar V="n"/> 
       <krankheit_in_mitteleuropa_sehr_selten V="j"/> 
       <schlüsselnummer_mit_inhalt_belegt V="j"/> 
       <infektionsschutzgesetz_meldepflicht V="j"/> 
       <infektionsschutzgesetz_abrechnungsbesonderheit V="j"/> 

Come si può vedere il mio primo nodo è KAPITEL. Mi piacerebbe fare qualcosa come kapitel .each do | f | in modo che nokgiri esegua i nodi von_icd_code e bis_icd_code nell'ordine corretto. Il mio codice:

require 'rubygems' 
    require 'nokogiri' 
    require 'open-uri' 

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

    kapitel = @doc.css('kapitel') 
    kapitel.each do |f| 
    puts f.css('von_icd_code') 
    puts f.css('bis_icd_code') 
    end 

Il problema è che non Nogiri EXTRAKT il 'von_icd_code' e 'bis_icd_code' nel oder destra, invece un primo momento elencare tutti von_icd_code e poi all 'bis_icd_code'. Come posso estrapolare i nodi nel modo giusto?

E nella mia uscita ottengo:

<von_icd_code V="A00"/> 

Come posso ottenere solo il contenuto del V in questo caso A00

Grazie!

risposta

5

Dal bis_icd_code segue ogni von_icd_code, la scelta più ovvia è css + prossima adiacente selettore di pari livello:

doc.css('von_icd_code').each do |icd| 
    puts icd['V'] 
    puts icd.at('+ bis_icd_code')['V'] 
end 
#=> A00 
#=> B99 
#=> A00 
#=> A09 
+0

Questo si basa sul fatto che 'bis_icd_code' appare sempre * dopo *' von_icd_code' in coppia. Potrebbero farlo, ma non ci sono prove di ciò. – Borodin

+0

Ovviamente ce ne sono prove. Guarda l'esempio. – pguardiario

5

È possibile utilizzare il metodo di Nokogiri traverse, che, beh, attraversa tutti i nodi XML in modo ricorsivo.

Il vostro esempio sarà quindi simile a questa:

names = %w(von_icd_code bis_icd_code) 
@doc.traverse {|node| p node['V'] if names.include? node.name} 

Ed esso stampa

"A00" 
"B99" 
"A00" 
"A09" 

C'è un sacco di cose pulite nel Nokogiri::Node, che ci permettono di fare le cose davvero cool con ancora i file XML più complessi. Per una breve lista, puoi dare un'occhiata a at this cheat sheet.

Buona fortuna!

+0

Grazie, hai qualche idee come potrei risolvere il mio primo numero, in modo che i nodi vengono visualizzati nel oder giusto? –

+1

Lo fanno già, se cambiamo il codice da 'p node ['V']' a 'p node.name', avremo i nodi nel giusto ordine. –

+0

Scusa, ma ottengo il testo del testo di output icd_code ...! Il mio codice: names =% w (von_icd_code bis_icd_code) @ doc.traverse {| node | nodo p ['V'] se nomi.include? puts node.name} –

2

Aggiornamento

Mi dispiace, questo non funziona con i selettori CSS. Usa invece XPath. E per quanto riguarda la tua domanda secondaria, è possibile accedere a Nokogiri tramite node['V']. Ti piace questa uscita

kapitel = @doc.xpath('//kapitel') 
kapitel.each do |f| 
    f.xpath('//von_icd_code | //bis_icd_code').each do |node| 
    puts node['V'] 
    end 
end 

A00 
B99 
A00 
A09 

È possibile risolvere questo problema senza la stravaganza del traverse scrivendo

kapitel.each do |f| 
    puts f.css('von_icd_code, bis_icd_code') 
end 
+0

Si dice che non funziona con i selettori CSS, quindi si dimostra che lo fa. Scegli un lato. – pguardiario

+0

@pguardiario: L'aggiornamento, utilizzando XPath, funziona correttamente. L'originale, che usa il CSS, scorre tutti gli elementi 'von_icd_code' e quindi attraverso gli elementi' bis_ice_code'. – Borodin