2009-08-13 2 views
14

Voglio estrarre parti di un file XML e prendere nota che ho estratto parte di quel file, come "qui qualcosa è stato estratto".Inserimento ed eliminazione di nodi ed elementi XML usando Nokogiri

che sto cercando di fare questo con Nokogiri, ma sembra in realtà non essere documentata su come:

  1. eliminare tutti i bambini di un cambiamento <Nokogiri::XML::Element>
  2. la inner_text di quell'elemento completa

Degli indizi?

+0

Esercitazioni di Nokogiri per [Modifica di un HTML/XML Document] (http://nokogiri.org/tutorials/modifying_an_html_xml_document.html) copre questo. Anche 'node.unlink' lo rimuoverà da un DOM. –

+0

Vedere "[chiedere]". Ad esempio, mancano informazioni importanti come un esempio XML minimo per l'input e l'output previsto, oltre al codice che è stato scritto per risolvere il problema. –

risposta

3

Si può fare in questo modo:

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

Mentre che sarebbe rimuovere tutti i bambini all'interno del tag <note>, io non sono sicuro di come a "cambiare l'inner_text" di tutti gli elementi di nota. Penso che inner_text non sia applicabile per un Nokogiri :: XML :: Element.

14

Nokogiri rende piuttosto facile. Utilizzando this document come esempio, il seguente codice troverà tutte vitamins tag, rimuovere i loro bambini (e figli dei figli, ecc), e cambiare il loro testo interno per dire "I bambini rimossi.":

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 dato food nodo andrà da guardare in questo modo:

<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 questo:

<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

l'esempio precedente Nokogiri mi trova nel r direzione ight, ma utilizzando doc.search lasciato un malformati //vitamins, quindi ho usato i 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 

che si traduce in:

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

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

Ecco quello che farei:

parse un po 'di XML prima:

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 

Se voglio eliminare il contenuto di un nodo, posso rem ove la sua children o assegnare nullo al suo contenuto:

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\"/>" 

Se voglio per estrarre il testo da un nodo per l'uso in qualche altro modo:

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 comunque si voglia manipolare il testo.

E, se si desidera contrassegnare che hai rimosso il testo:

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

Si potrebbe anche usare un commento XML invece:

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