Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating XML nodes using Nokogiri

Tags:

xml

ruby

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 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.

like image 632
Todd Matthews Avatar asked Oct 28 '14 05:10

Todd Matthews


2 Answers

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.

like image 164
the Tin Man Avatar answered Nov 20 '22 07:11

the Tin Man


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.

like image 29
dcorr Avatar answered Nov 20 '22 08:11

dcorr