2011-07-13 28 views
12

Estoy intentando usar Ruby's Nokogiri para analizar grandes archivos XML (1 GB o más). Estoy probando el código en un archivo más pequeño, que contiene solo 4 registros available here. Estoy usando Nokogiri versión 1.5.0, Ruby 1.8.7 en Ubuntu 10.10. Como no entiendo muy bien SAX, estoy intentando que Nokogiri :: XML :: Reader comience.¿Cómo uso Nokogiri :: XML :: Reader para analizar grandes archivos XML?

Mi primer intento, para recuperar el contenido de la etiqueta PMID, se parece a esto:

#!/usr/bin/ruby 
require "rubygems" 
require "nokogiri" 

file = ARGV[0] 
reader = Nokogiri::XML::Reader(File.open(file)) 
p  = [] 
reader.each do |node| 
    if node.name == "PMID" 
    p << node.inner_xml 
    end 
end 

puts p.inspect 

Esto es lo que esperaba ver:

["21714156", "21693734", "21692271", "21692260"] 

Esto es lo que realmente vi:

["21714156", "", "21693734", "", "21692271", "", "21692260", ""] 

Parece que, por alguna razón, mi código es encontrar, o generar, una etiqueta PMID vacía adicional para cada instancia e de PMID. O eso o inner_xml no funciona como pensé.

Estaría agradecido si alguien pudiera confirmar que mi código y mis datos generan el resultado mostrado y sugieren dónde me estoy equivocando.

+0

En los "viejos tiempos", antes de tener hosts con muchos GB de RAM, solíamos preocuparnos por cargar uno o dos GB de contenido. Ahora, a menos que haya riesgos de recibir un archivo inesperado que consumiría toda la memoria RAM disponible, trataría de permitir que Nokogiri y Ruby extraigan el archivo de tamaño completo. Sí, 1GB es mucho texto, pero en un sistema de 8GB o 16GB no es nada. Observe para ver si la carga y el tiempo de procesamiento mejoran o se ven afectados ya que la asignación de memoria y la recolección de basura pueden afectar la velocidad; Usar el modelo SAX puede ayudar en ese caso, pero prefiero cargarlo y tratarlo como un DOM. –

+0

La velocidad es más un problema que la RAM. Por ejemplo, traté de analizar con Hpricot (mi biblioteca preferida) en un servidor compartido con 96 GB de RAM: 72 minutos. – neilfws

+0

No he estado siguiendo Hpricot por un par de años; Lo usé mucho pero me encontré con algunos problemas en los que explotaba consistentemente de una manera gloriosa, y Nokogiri no, así que cambié y no miré hacia atrás. 72 minutos parece mucho tiempo para correr. Puede intentar ejecutar el generador de perfiles y ver si revela algo. De lo contrario, resuma el código y XML y publíquelo aquí y trataremos de ayudar a acelerar las cosas. –

Respuesta

18

Cada elemento en la secuencia viene a través de dos eventos: uno para abrir el elemento y otro para cerrarlo. El acto de inauguración tendrá

node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT 

y el acto de clausura tendrá

node.node_type == Nokogiri::XML::Reader::TYPE_END_ELEMENT 

Las cadenas vacías que estamos viendo son sólo el elemento de cierre de eventos. Recuerda que con el análisis SAX, básicamente estás caminando por un árbol, por lo que necesitas el segundo evento para decirte cuándo vas a volver a subir y cerrar un elemento.

es probable que desee algo más parecido a esto:

reader.each do |node| 
    if node.name == "PMID" && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT 
    p << node.inner_xml 
    end 
end 

O quizás:

reader.each do |node| 
    next if node.name  != 'PMID' 
    next if node.node_type != Nokogiri::XML::Reader::TYPE_ELEMENT 
    p << node.inner_xml 
end 

o alguna otra variación sobre el mismo.

+0

Su primera solución funciona; muchas gracias. – neilfws

+0

por qué no probar esto - https://github.com/amolpujari/reading-huge-xml –

Cuestiones relacionadas