2011-03-15 4 views
6

J'ai un simple fichier XML, items.xml:Comment ajouter un nouveau nœud XML

<?xml version="1.0" encoding="UTF-8" ?> 

<items> 
    <item> 
    <name>mouse</name> 
    <manufacturer>Logicteh</manufacturer> 
    </item> 
    <item> 
    <name>keyboard</name> 
    <manufacturer>Logitech - Inc.</manufacturer> 
    </item> 
    <item> 
    <name>webcam</name> 
    <manufacturer>Logistech</manufacturer> 
    </item> 
</items> 

Je suis en train d'insérer un nouveau noeud avec le code suivant:

require 'rubygems' 
require 'nokogiri' 

f = File.open('items.xml') 
@items = Nokogiri::XML(f) 
f.close 

price = Nokogiri::XML::Node.new "price", @items 
price.content = "10" 

@items.xpath('//items/item/manufacturer').each do |node| 
    node.add_next_sibling(price) 
end 

file = File.open("items_fixed.xml",'w') 
file.puts @items.to_xml 
file.close 

Cependant ce code ajoute un nouveau noeud seulement après le dernier noeud <manufacturer>, items_fixed.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<items> 
    <item> 
    <name>mouse</name> 
    <manufacturer>Logitech</manufacturer> 
    </item> 
    <item> 
    <name>keyboard</name> 
    <manufacturer>Logitech</manufacturer> 
    </item> 
    <item> 
    <name>webcam</name> 
    <manufacturer>Logitech</manufacturer><price>10</price> 
    </item> 
</items> 

Pourquoi?

+0

Vous rendez cela trop difficile. Nokogiri facilite l'ajout de nœuds à l'aide d'une chaîne, qu'il analyse ensuite dans un nouveau nœud. Voir ma réponse ci-dessous. –

Répondre

12

Il serait utile de faire la distinction entre un Node (un élément particulier de données XML structurées à un endroit particulier dans un arbre), et un «modèle de nœud» qui est la structure des données.

Nokogiri (et la plupart des autres bibliothèques XML) ne vous permettent de spécifier Node s, nœud pas de modèles. Donc, lorsque vous avez créé price = Nokogiri::XML::Node.new "price", @items, vous aviez une donnée particulière qui appartenait à un endroit particulier, mais qui n'avait pas encore défini le lieu.

Lorsque vous avez ajouté à la première <item>, vous avez défini sa place. Lorsque vous l'avez ajouté à la seconde <item>, vous l'avez déraciné de sa place et l'avez placé dans un nouvel endroit. À ce stade, ce Node est apparu seulement dans le second <item>. Cela continue lorsque vous ajoutez le même Node à chaque élément, jusqu'à ce que vous atteigniez le dernier <item>, qui est l'endroit où le nœud reste.

Nokogiri n'a aucun moyen de spécifier un modèle de nœud. Ce que vous devez faire est:

@items.xpath('//items/item/manufacturer').each do |node| 
    price = Nokogiri::XML::Node.new "price", @items 
    price.content = "10" 
    node.add_next_sibling(price) 
end 
+0

J'ai vu le comportement exact que vous avez expliqué dans le débogueur mais je ne pouvais pas le comprendre. Merci pour votre explication et votre réponse! –

+2

Alternativement, vous pouvez simplement utiliser [ 'noeud # dup'] (http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Node.html#M000469) pour cloner le noeud avant de l'insérer dans un nouvel emplacement . – Phrogz

+0

Belle explication .. J'avais le même problème depuis 3 ou 4 jours. Maintenant, j'ai découvert pourquoi cela se passait. Merci pour l'OP et vous. –

2

Je commencerai par ceci:

require 'nokogiri' 

doc = Nokogiri::XML(<<EOT) 
<?xml version="1.0" encoding="UTF-8"?> 
<items> 
    <item> 
    <name>mouse</name> 
    <manufacturer>Logitech</manufacturer> 
    </item> 
    <item> 
    <name>keyboard</name> 
    <manufacturer>Logitech - Inc.</manufacturer> 
    </item> 
</items> 
EOT 

doc.search('manufacturer').each { |n| n.after('<price>10</price>') } 

qui se traduit par:

puts doc.to_xml 
# >> <?xml version="1.0" encoding="UTF-8"?> 
# >> <items> 
# >> <item> 
# >>  <name>mouse</name> 
# >>  <manufacturer>Logitech</manufacturer><price>10</price> 
# >> </item> 
# >> <item> 
# >>  <name>keyboard</name> 
# >>  <manufacturer>Logitech - Inc.</manufacturer><price>10</price> 
# >> </item> 
# >> </items> 

Il est facile de construire sur ce pour insérer des valeurs différentes pour le prix.

Questions connexes