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 adds a new node only 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?
It would be helpful to distinguish between a
Node
(a particular piece of structured XML data at a particular place in a tree), and a "node template" which is the structure of the data.Nokogiri (and most other XML libraries) only allow you to specify
Node
s, not node templates. So when you createdprice = Nokogiri::XML::Node.new "price", @items
, you had a particular piece of data that belongs in a particular place, but hadn't defined the place yet.When you added it to the first
<item>
, you defined its place. When you added it to the second<item>
, you uprooted it from its place and put it in a new place. At that point thisNode
appeared only in the second<item>
. This continues when you add the sameNode
to each item, until you reach the last<item>
, which is where the node stays.Nokogiri doesn't have any way to specify a node template. What you need to do is:
I'd start with this:
Which results in:
It's easy to build upon this to insert different values for the price.