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 the file like so:
<mainnode>
<secnode>
<data1></data2>
<data2></data2>
</secnode>
<secnode>
<data1></data2>
<data2></data2>
</secnode>
</mainnode>
I am having trouble getting the concept of adding nodes with 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 to not be of much help in this area and have not made it past just adding the <secnode>
node as a child of <mainnode>
.
Any help is appreciated.
Adding nodes in Nokogiri is a lot easier than you think it is, but your question isn't 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 run, results in:
<?xml version="1.0"?>
<mainnode>
<secnode>
<data1/>
<data2/>
</secnode>
<secnode>
<data1/>
<data2/>
</secnode></mainnode>
The funky alignment is the result of appending the intervening text nodes used for indentation. The resulting XML is valid.
If you're adding a different set of nodes, it's still easy:
require '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
Which outputs:
<?xml version="1.0"?>
<mainnode>
<secnode>
<data1/>
<data2/>
</secnode>
<secnode>
<data3/>
<data4/>
</secnode>
</mainnode>
You can use that 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
Which looks like:
<?xml version="1.0"?>
<mainnode>
<secnode>
<data1/>
<data2/>
</secnode>
<secnode>
<data3>foo</data3>
<data4>bar</data4>
</secnode>
</mainnode>
Nokogiri makes it very easy to create nodes to be added by using string representations of the XML or HTML, which it then converts on the fly.
require 'nokogiri'
def parse_xml_file(file_name)
f = File.read(file_name)
Nokogiri::XML(f) # do not need variable here; it's 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'
isn't doing anything and will throw an error; you haven't selected anything from the XML document yet.
You should read up on traversing an XML DOM and selecting nodes. Try this primer: https://blog.engineyard.com/2010/getting-started-with-nokogiri
You say you read the Nokogiri docs, but I'd go back and re-read this, too: http://www.nokogiri.org/tutorials/searching_a_xml_html_document.html
Finally, play around with nokogiri by parsing a doc in IRB and seeing what you can do with it. That's a good way to explore and get a feel for nokogiri.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With