mouse

How to add a new node to XML

I have a simple XML file, items.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> 

I am trying to insert a new node with the following code:

 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 

However, this code only adds a new node after the last <manufacturer> node, 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> 

Why?

+6
ruby xml nokogiri
source share
2 answers

It would be useful to distinguish between Node (a specific piece of structured XML data at a specific location in the tree) and the node template, which is the data structure.

Nokogiri (and most other XML libraries) allows you to specify Node s patterns, not nodes. Therefore, when you created price = Nokogiri::XML::Node.new "price", @items , you had a specific piece of data that belongs to a specific location but did not yet define a location.

When you added it to the first <item> , you determined its place. When you added it to the second <item> , you pulled it out of your place and placed it in a new place. At this moment, this Node appeared only in the second <item> . This continues when you add the same Node to each element until you reach the last <item> where the node is located.

Nokogiri has no way to specify a node pattern. What you need to do:

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

I would start with this:

 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>') } 

Result:

 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> 

With this, it is easy to insert different values ​​for the price.

+2
source share

All Articles