Creating XML Nodes with Nokogiri
I am having problems creating nodes and adding them to an XML file:
<mainnode>
<secnode>
<data1></data2>
<data2></data2>
</secnode>
</mainnode>
I want to be able to add to a file like so:
<mainnode>
<secnode>
<data1></data2>
<data2></data2>
</secnode>
<secnode>
<data1></data2>
<data2></data2>
</secnode>
</mainnode>
I am having problems getting the concept of adding nodes using Nokogiri.
This is my current code:
def openXML
f = File.open("file.xml")
doc = Nokogiri::XML(f)
end
def parseXML
mainnode.name = 'mainnode'
f = openXML
temp = Nokogiri::XML::Node.new "secnode", f
mainnode.add_next_sibling(temp)
end
What concepts am I missing?
I need to be able to add instance variables to <data1>
and <data2>
, but I found the Nokogiri tutorial not very helpful in this area and didn't skip it by just adding <secnode>
node as a child <mainnode>
.
Any help is appreciated.
source to share
Adding nodes to Nokigiri is much easier than you think, but your question is not very clear.
If you want to duplicate an existing node:
require 'nokogiri'
xml = <<EOT
<mainnode>
<secnode>
<data1></data2>
<data2></data2>
</secnode>
</mainnode>
EOT
doc = Nokogiri::XML(xml)
secnode = doc.at('secnode')
doc.root.add_child secnode.dup
puts doc.to_xml
Which, when launched, results in:
<?xml version="1.0"?>
<mainnode>
<secnode>
<data1/>
<data2/>
</secnode>
<secnode>
<data1/>
<data2/>
</secnode></mainnode>
Funky alignment is the result of adding intermediate text nodes used for indentation. The resulting XML is valid.
If you add another set of nodes, it's still easy:
requires "nokogiri"
xml = <<EOT
<mainnode>
<secnode>
<data1></data2>
<data2></data2>
</secnode>
</mainnode>
EOT
node_to_add = <<EOT
<secnode>
<data3 />
<data4 />
</secnode>
EOT
doc = Nokogiri::XML(xml)
doc.root.add_child node_to_add
puts doc.to_xml
What are the outputs:
<?xml version="1.0"?>
<mainnode>
<secnode>
<data1/>
<data2/>
</secnode>
<secnode>
<data3/>
<data4/>
</secnode>
</mainnode>
You can use this as a template:
require 'nokogiri'
xml = <<EOT
<mainnode>
<secnode>
<data1></data2>
<data2></data2>
</secnode>
</mainnode>
EOT
v1 = 'foo'
v2 = 'bar'
node_to_add = <<EOT
<secnode>
<data3>#{ v1 }</data3>
<data4>#{ v2 }</data4>
</secnode>
EOT
doc = Nokogiri::XML(xml)
doc.root.add_child node_to_add
puts doc.to_xml
What looks like:
<?xml version="1.0"?>
<mainnode>
<secnode>
<data1/>
<data2/>
</secnode>
<secnode>
<data3>foo</data3>
<data4>bar</data4>
</secnode>
</mainnode>
Nokogiri makes it easy to create nodes that are added using XML or HTML string representations, which are then converted on the fly.
source to share
require 'nokogiri'
def parse_xml_file(file_name)
f = File.read(file_name)
Nokogiri::XML(f) # do not need variable here; it the return value of the method
end
def add_element(doc, node_name)
new_element = Nokogiri::XML::Node.new(node_name, doc)
new_element.content = "anything"
doc.root.add_child(new_element)
end
doc = parse_xml_file("sample.xml")
add_element(doc, 'secnode')
puts doc.to_s
Your line mainnode.name = 'mainnode'
does nothing and throws an error; you haven't selected anything from the XML document yet.
You should read about XML DOM traversal and node selection. Try this primer: https://blog.engineyard.com/2010/getting-started-with-nokogiri
You say you are reading the Nokogiri docs, but I'll come back and re-read that too: http://www.nokogiri.org/tutorials/searching_a_xml_html_document.html
Finally, play with nokogiri by parsing the document in IRB and seeing what you can do with it. This is a good way to explore and feel the nookogiri.
source to share