2009-08-13 41 views
14

Quiero extraer partes de un archivo XML y hacer una nota de que extraje alguna parte en ese archivo, como "aquí se extrajo algo".Insertar y eliminar nodos XML y elementos usando Nokogiri

que estoy tratando de hacer esto con Nokogiri, pero parece que no es realmente ser documentados sobre cómo:

  1. eliminar todas niño de un cambio <Nokogiri::XML::Element>
  2. la inner_text de ese elemento completo

¿Alguna pista?

+0

tutoriales de Nokogiri para [Modificación de un HTML/XML Documento] (http://nokogiri.org/tutorials/modifying_an_html_xml_document.html) cubre esto. También 'node.unlink' lo eliminará de un DOM. –

+0

Ver "[preguntar]". Como está, falta información importante, como un ejemplo XML mínimo para la entrada y el resultado esperado, más el código que se escribió para resolver el problema. –

Respuesta

3

Puede hacerlo de esta manera:

doc=Nokogiri::XML(your_document) 
note=doc.search("note") # find all tags with the node_name "note" 
note.remove 

Mientras que eliminaría todos los niños dentro de la etiqueta <note>, no estoy seguro de cómo "cambiar el inner_text" de todas las notas. Creo que inner_text no es aplicable para un elemento Nokogiri :: XML ::.

14

Nokogiri hace que esto sea bastante fácil. Usando this document como ejemplo, el siguiente código encontrará todos vitamins etiquetas, retire sus hijos (y los hijos de los hijos, etc.), y cambiar su texto interno que decir "niños retirados.":

require 'nokogiri' 

io = File.open('sample.xml', 'r') 
doc = Nokogiri::XML(io) 
io.close 

doc.search('//vitamins').each do |node| 
    node.children.remove 
    node.content = 'Children removed.' 
end 

un hecho food nodo pasará de este aspecto:

<food> 
    <name>Avocado Dip</name> 
    <mfr>Sunnydale</mfr> 
    <serving units="g">29</serving> 
    <calories total="110" fat="100"/> 
    <total-fat>11</total-fat> 
    <saturated-fat>3</saturated-fat> 
    <cholesterol>5</cholesterol> 
    <sodium>210</sodium> 
    <carb>2</carb> 
    <fiber>0</fiber> 
    <protein>1</protein> 
    <vitamins> 
     <a>0</a> 
     <c>0</c> 
    </vitamins> 
    <minerals> 
     <ca>0</ca> 
     <fe>0</fe> 
    </minerals> 
</food> 

a esto:

<food> 
    <name>Avocado Dip</name> 
    <mfr>Sunnydale</mfr> 
    <serving units="g">29</serving> 
    <calories total="110" fat="100"/> 
    <total-fat>11</total-fat> 
    <saturated-fat>3</saturated-fat> 
    <cholesterol>5</cholesterol> 
    <sodium>210</sodium> 
    <carb>2</carb> 
    <fiber>0</fiber> 
    <protein>1</protein> 
    <vitamins>Children removed.</vitamins> 
    <minerals> 
     <ca>0</ca> 
     <fe>0</fe> 
    </minerals> 
</food> 
3

el ejemplo anterior Nokogiri me puso en el r dirección de vuelo, pero utilizando doc.search dejaron un mal formado //vitamins, por lo que utilizan CSS:

require "rubygems" 
require "nokogiri" 

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

doc.css("food vitamins").each do |node| 
    puts "\r\n[debug] Before: vitamins= \r\n#{node}" 
    node.children.remove 
    node.content = "Children removed" 
    puts "\r\n[debug] After: vitamins=\r\n#{node}" 
end 
f.close 

que se traduce en:

debug] Before: vitamins= 
<vitamins> 
     <a>0</a> 
     <c>0</c> 
    </vitamins> 

[debug] After: vitamins= 
<vitamins>Children removed</vitamins> 
2

Esto es lo que haría:

PARSE alguna XML en primer lugar:

require 'nokogiri' 

doc = Nokogiri::XML(<<EOT) 
<?xml version="1.0"?> 
<?xml-stylesheet type="text/css" href="nutrition.css"?> 
<nutrition> 

    <daily-values> 
    <total-fat units="g">65</total-fat> 
    <saturated-fat units="g">20</saturated-fat> 
    <cholesterol units="mg">300</cholesterol> 
    <sodium units="mg">2400</sodium> 
    <carb units="g">300</carb> 
    <fiber units="g">25</fiber> 
    <protein units="g">50</protein> 
    </daily-values> 

    <food> 
    <name>Avocado Dip</name> 
    <mfr>Sunnydale</mfr> 
    <serving units="g">29</serving> 
    <calories total="110" fat="100"/> 
    <total-fat>11</total-fat> 
    <saturated-fat>3</saturated-fat> 
    <cholesterol>5</cholesterol> 
    <sodium>210</sodium> 
    <carb>2</carb> 
    <fiber>0</fiber> 
    <protein>1</protein> 
    <vitamins> 
     <a>0</a> 
     <c>0</c> 
    </vitamins> 
    <minerals> 
     <ca>0</ca> 
     <fe>0</fe> 
    </minerals> 
    </food> 

</nutrition> 
EOT 

Si deseo eliminar el contenido de un nodo, puedo eliminar ove su children o asignar cero a su contenido:

doc.at('total-fat').to_xml # => "<total-fat units=\"g\">65</total-fat>" 
doc.at('total-fat').children.remove 
doc.at('total-fat').to_xml # => "<total-fat units=\"g\"/>" 

o:

doc.at('saturated-fat').to_xml # => "<saturated-fat units=\"g\">20</saturated-fat>" 
doc.at('saturated-fat').content = nil 
doc.at('saturated-fat').to_xml # => "<saturated-fat units=\"g\"/>" 

Si quiero extraer el texto de un nodo para el uso de alguna otra manera:

food = doc.at('food').text 
# => "\n Avocado Dip\n Sunnydale\n 29\n \n 11\n 3\n 5\n 210\n 2\n 0\n 1\n \n  0\n  0\n \n \n  0\n  0\n \n " 

o :

food = doc.at('food').children.map(&:text) 
# => ["\n ", 
#  "Avocado Dip", 
#  "\n ", 
#  "Sunnydale", 
#  "\n ", 
#  "29", 
#  "\n ", 
#  "", 
#  "\n ", 
#  "11", 
#  "\n ", 
#  "3", 
#  "\n ", 
#  "5", 
#  "\n ", 
#  "210", 
#  "\n ", 
#  "2", 
#  "\n ", 
#  "0", 
#  "\n ", 
#  "1", 
#  "\n ", 
#  "\n  0\n  0\n ", 
#  "\n ", 
#  "\n  0\n  0\n ", 
#  "\n "] 

o cualquier otra cosa que quiera manipular el texto.

Y, si desea marcar que ha eliminado el texto:

doc.at('food').content = 'REMOVED' 
doc.at('food').to_xml # => "<food>REMOVED</food>" 

También es posible usar un comentario XML en lugar:

doc.at('food').children = '<!-- REMOVED -->' 
doc.at('food').to_xml # => "<food>\n <!-- REMOVED -->\n</food>" 
Cuestiones relacionadas