# Ruby and XML

**URL:** <https://rubytalk.org/t/ruby-and-xml/63516>\
**Category:** ruby-talk\
**Created:** [4 September 2011 19:02 UTC](https://rubytalk.org/t/ruby-and-xml/63516 "2011-09-04T19:02:25Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Bob\_Aiello1](https://avatars.discourse-cdn.com/v4/letter/b/a8b319/32.png) [@Bob\_Aiello1](https://rubytalk.org/u/Bob_Aiello1)\
**Post date:** [4 September 2011 19:02 UTC](https://rubytalk.org/t/ruby-and-xml/63516/1 "2011-09-04T19:02:25Z")

</div>

Hi Everyone,

I am new to Ruby and trying to use it to parse XML files so that I can verify that name/value pairs in two (or more) XML files are defined consistently

I have been trying to use the rexml API  
[http://www.germane-software.com/software/rexml/](http://www.germane-software.com/software/rexml/)

The website has been down a lot lately and I haven't found too many other sources for information

Here is a snippet of my code

require "rexml/document"  
include REXML

file1 = File.new( "test.xml" )  
doc1 = REXML::Document.new file1  
names1 = XPath.each(doc1, "//name") { |e|}  
values1 = XPath.each(doc1, "//value") { |e|}  
now I can parse names1 and values1 and then do the same for the second XML file.  
This approach is not great because it does ensure that the name/value pairs are siblings.

I am wondering if there is a better way to do this.

Any help would be great appreciated. BTW - I would welcome articles on using Ruby for configuration, release and deployment management on CM Crossroads ([www.cmcrossroads.com](http://www.cmcrossroads.com))

Bob Aiello  
[http://www.linkedin.com/in/BobAiello](http://www.linkedin.com/in/BobAiello)  
[bob.aiello@ieee.org](mailto:bob.aiello@ieee.org)

---

<div class="post-metadata">

**Author:** ![Steve\_Klabnik](https://avatars.discourse-cdn.com/v4/letter/s/0ea827/32.png) [@Steve\_Klabnik](https://rubytalk.org/u/Steve_Klabnik)\
**Post date:** [4 September 2011 19:10 UTC](https://rubytalk.org/t/ruby-and-xml/63516/2 "2011-09-04T19:10:21Z")

</div>

Rexml is in the standard library, but is slow and awkward. Try  
nokogiri instead: [http://nokogiri.org/](http://nokogiri.org/)

---

<div class="post-metadata">

**Author:** ![11142](https://avatars.discourse-cdn.com/v4/letter/1/e0b2c6/32.png) [@11142](https://rubytalk.org/u/11142)\
**Post date:** [4 September 2011 19:12 UTC](https://rubytalk.org/t/ruby-and-xml/63516/3 "2011-09-04T19:12:29Z")

</div>

First of all, I'd recommend you a different library. Personalyl I  
found REXML awkward to use, Nokogiri (`gem install nokogiri`) is much  
better. (It also parses HTML.)

We'll probably need the XML file to be able to help you.

-- Matma Rex

---

<div class="post-metadata">

**Author:** ![Gavin\_Kistner4](https://avatars.discourse-cdn.com/v4/letter/g/ecccb3/32.png) [@Gavin\_Kistner4](https://rubytalk.org/u/Gavin_Kistner4)\
**Post date:** [4 September 2011 19:15 UTC](https://rubytalk.org/t/ruby-and-xml/63516/4 "2011-09-04T19:15:11Z")

</div>

Welcome to Ruby. I concur with the other post that Nokogiri is even better than REXML.

I don't fully understand your goal or the problem you mentioned about siblings. Can you post a small sample XML and the output you'd like to get from it?

> **···**
>
> --  
> (-, /\ \/ / /\/
> 
> On Sep 4, 2011, at 1:02 PM, Bob Aiello \<raiello@acm.org\> wrote:
> 
> > Hi Everyone,
> > 
> > I am new to Ruby and trying to use it to parse XML files so that I can verify that name/value pairs in two (or more) XML files are defined consistently
> > 
> > I have been trying to use the rexml API  
> > [http://www.germane-software.com/software/rexml/](http://www.germane-software.com/software/rexml/)
> > 
> > The website has been down a lot lately and I haven't found too many other sources for information
> > 
> > Here is a snippet of my code
> > 
> > require "rexml/document"  
> > include REXML
> > 
> > file1 = File.new( "test.xml" )  
> > doc1 = REXML::Document.new file1  
> > names1 = XPath.each(doc1, "//name") { |e|}  
> > values1 = XPath.each(doc1, "//value") { |e|}  
> > now I can parse names1 and values1 and then do the same for the second XML file.  
> > This approach is not great because it does ensure that the name/value pairs are siblings.
> > 
> > I am wondering if there is a better way to do this.
> > 
> > Any help would be great appreciated. BTW - I would welcome articles on using Ruby for configuration, release and deployment management on CM Crossroads (www.cmcrossroads.com)
> > 
> > Bob Aiello  
> > [http://www.linkedin.com/in/BobAiello](http://www.linkedin.com/in/BobAiello)  
> > bob.aiello@ieee.org

---

<div class="post-metadata">

**Author:** ![Chris\_White](https://avatars.discourse-cdn.com/v4/letter/c/e56c9b/32.png) [@Chris\_White](https://rubytalk.org/u/Chris_White)\
**Post date:** [4 September 2011 19:19 UTC](https://rubytalk.org/t/ruby-and-xml/63516/5 "2011-09-04T19:19:20Z")

</div>

> Here is a snippet of my code
> 
> require "rexml/document"  
> include REXML
> 
> file1 = File.new( "test.xml" )  
> doc1 = REXML::Document.new file1  
> names1 = XPath.each(doc1, "//name") { |e|}  
> values1 = XPath.each(doc1, "//value") { |e|}  
> now I can parse names1 and values1 and then do the same for the second  
> XML file.  
> This approach is not great because it does ensure that the name/value  
> pairs are siblings.

Can you provide this test.xml file or a sample file like it, and what the expected output is?  
PS: Some docs for ReXML, which is now part of the Ruby standard library:[http://furious-waterfall-55.heroku.com/yard\_stdlib/REXML.html](http://furious-waterfall-55.heroku.com/yard_stdlib/REXML.html)  
Regards,Chris WhiteTwitter: [http://www.twitter.com/cwgem](http://www.twitter.com/cwgem)

---

<div class="post-metadata">

**Author:** ![7stud](https://avatars.discourse-cdn.com/v4/letter/7/57b2e6/32.png) [@7stud](https://rubytalk.org/u/7stud)\
**Post date:** [5 September 2011 07:28 UTC](https://rubytalk.org/t/ruby-and-xml/63516/6 "2011-09-05T07:28:02Z")

</div>

\<?xml version="1.0"?\>  
\<note\>

&nbsp;&nbsp;\<name\>Tove\</name\>  
&nbsp;&nbsp;\<value\>Tove's value is: 10\</value\>  
&nbsp;&nbsp;\<garbage\>xxxx\</garbage\>

&nbsp;&nbsp;\<to\>Tove\</to\>  
&nbsp;&nbsp;\<from\>Jani\</from\>  
&nbsp;&nbsp;\<heading\>Reminder\</heading\>  
&nbsp;&nbsp;\<body\>Don't forget me this weekend!\</body\>

&nbsp;&nbsp;\<parent\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Jani\</name\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<value\>Jani's value is: 20\</value\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<garbage\>xxxx\</garbage\>  
&nbsp;&nbsp;\</parent\>

&nbsp;&nbsp;\<parent\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<name\>No sibling\</name\>  
&nbsp;&nbsp;\</parent\>  
&nbsp;&nbsp;\<value\>No sibling's value is: 30\</value\>

\</note\>

require 'rexml/document'

f = File.new("xml.xml")  
doc = REXML::Document.new(f)

REXML::XPath.each(doc, "//name") do |element|  
&nbsp;&nbsp;puts "name: #{element.text}"  
&nbsp;&nbsp;if sibling = element.next\_element  
&nbsp;&nbsp;&nbsp;&nbsp;puts sibling.text  
&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;puts "No \<value\> tag that is a sibling"  
&nbsp;&nbsp;end

&nbsp;&nbsp;puts "-" \* 20  
end

--output:--  
name: Tove  
Tove's value is: 10

> **···**
>
> --------------------  
> name: Jani  
> Jani's value is: 20  
> --------------------  
> name: No sibling  
> No \<value\> tag that is a sibling  
> --------------------
> 
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Gavin\_Kistner4](https://avatars.discourse-cdn.com/v4/letter/g/ecccb3/32.png) [@Gavin\_Kistner4](https://rubytalk.org/u/Gavin_Kistner4)\
**Post date:** [5 September 2011 13:01 UTC](https://rubytalk.org/t/ruby-and-xml/63516/7 "2011-09-05T13:01:11Z")

</div>

For comparison, here's one way to write code with the similar functionality using Nokogiri, but ensuring that the \<value\> element is a sibling of the \<name\> element. Unlike the above code, the following allows any number of elements between the \<name\> and the \<value\>:  
&nbsp;&nbsp;&nbsp;&nbsp;require 'nokogiri'

&nbsp;&nbsp;&nbsp;&nbsp;doc = Nokogiri::XML(IO.read("my.xml"))  
&nbsp;&nbsp;&nbsp;&nbsp;doc.search('name').each do |name|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "name: #{name.text}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if value=name.at\_xpath('following-sibling::value')  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts value.text  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "No \<value\> tag that is a sibling"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "-" \* 20  
&nbsp;&nbsp;&nbsp;&nbsp;end

Output:  
&nbsp;&nbsp;&nbsp;&nbsp;name: Tove  
&nbsp;&nbsp;&nbsp;&nbsp;Tove's value is: 10

> **···**
>
> On Sep 5, 2011, at 1:28 AM, 7stud -- wrote:
> 
> > require 'rexml/document'
> > 
> > f = File.new("xml.xml")  
> > doc = REXML::Document.new(f)
> > 
> > REXML::XPath.each(doc, "//name") do |element|  
> > puts "name: #{element.text}"  
> > if sibling = element.next\_element  
> > &nbsp;&nbsp;&nbsp;puts sibling.text  
> > else  
> > &nbsp;&nbsp;&nbsp;puts "No \<value\> tag that is a sibling"  
> > end
> > 
> > puts "-" \* 20  
> > end
> 
> &nbsp;&nbsp;&nbsp;&nbsp;--------------------  
> &nbsp;&nbsp;&nbsp;&nbsp;name: Jani  
> &nbsp;&nbsp;&nbsp;&nbsp;Jani's value is: 20  
> &nbsp;&nbsp;&nbsp;&nbsp;--------------------  
> &nbsp;&nbsp;&nbsp;&nbsp;name: No sibling  
> &nbsp;&nbsp;&nbsp;&nbsp;No \<value\> tag that is a sibling  
> &nbsp;&nbsp;&nbsp;&nbsp;--------------------
> 
> Again using this XML:  
> &nbsp;&nbsp;&nbsp;&nbsp;\<?xml version="1.0"?\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<note\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Tove\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<value\>Tove's value is: 10\</value\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<garbage\>xxxx\</garbage\>  
> &nbsp;&nbsp;  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<to\>Tove\</to\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<from\>Jani\</from\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<heading\>Reminder\</heading\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<body\>Don't forget me this weekend!\</body\>
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<parent\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Jani\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<value\>Jani's value is: 20\</value\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<garbage\>xxxx\</garbage\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</parent\>
> 
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<parent\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>No sibling\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</parent\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<value\>No sibling's value is: 30\</value\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\</note\>

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [5 September 2011 14:30 UTC](https://rubytalk.org/t/ruby-and-xml/63516/8 "2011-09-05T14:30:29Z")

</div>

Gavin Kistner wrote in post #1020210:

> > &nbsp;&nbsp;&nbsp;puts "No \<value\> tag that is a sibling"  
> > end
> > 
> > puts "-" \* 20  
> > end
> 
> For comparison, here's one way to write code with the similar  
> functionality using Nokogiri, but ensuring that the \<value\> element is a  
> sibling of the \<name\> element. Unlike the above code, the following  
> allows any number of elements between the \<name\> and the \<value\>:  
> &nbsp;&nbsp;&nbsp;&nbsp;require 'nokogiri'
> 
> &nbsp;&nbsp;&nbsp;&nbsp;doc = Nokogiri::XML(IO.read("my.xml"))  
> &nbsp;&nbsp;&nbsp;&nbsp;doc.search('name').each do |name|  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "name: #{name.text}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if value=name.at\_xpath('following-sibling::value')  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts value.text  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "No \<value\> tag that is a sibling"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "-" \* 20  
> &nbsp;&nbsp;&nbsp;&nbsp;end

You can even use an XPath expression to find names which do not have  
proper values:

//name[not(following-sibling::value)]  
//name[following-sibling::\*[1][name()!="value"]]  
//name[count(following-sibling::value)!=1]  
//name[following-sibling::\*[1][name()!="value"]]|//name[count(following-sibling::value)!=1]

attached and also here: [Solutions for ruby-talk 387408 · GitHub](https://gist.github.com/1195114)

Kind regards

robert

Attachments:  
[http://www.ruby-forum.com/attachment/6578/nv.rb](http://www.ruby-forum.com/attachment/6578/nv.rb)

> **···**
>
> > On Sep 5, 2011, at 1:28 AM, 7stud -- wrote:
> 
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![7stud](https://avatars.discourse-cdn.com/v4/letter/7/57b2e6/32.png) [@7stud](https://rubytalk.org/u/7stud)\
**Post date:** [5 September 2011 16:28 UTC](https://rubytalk.org/t/ruby-and-xml/63516/9 "2011-09-05T16:28:10Z")

</div>

Gavin Kistner wrote in post #1020210:

> For comparison, here's one way to write code with the similar  
> functionality using Nokogiri, but ensuring that the \<value\> element is a  
> sibling of the \<name\> element. Unlike the above code, the following  
> allows any number of elements between the \<name\> and the \<value\>:  
> &nbsp;&nbsp;&nbsp;&nbsp;require 'nokogiri'
> 
> &nbsp;&nbsp;&nbsp;&nbsp;doc = Nokogiri::XML(IO.read("my.xml"))  
> &nbsp;&nbsp;&nbsp;&nbsp;doc.search('name').each do |name|  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "name: #{name.text}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if value=name.at\_xpath('following-sibling::value')  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts value.text  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "No \<value\> tag that is a sibling"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "-" \* 20  
> &nbsp;&nbsp;&nbsp;&nbsp;end

I couldn't figure out the syntax for xpath's following-sibling, but now  
that I see it in your code, here it is in REXML:

require 'rexml/document'

f = File.new("xml.xml")  
doc = REXML::Document.new(f)

REXML::XPath.each(doc, "//name") do |element|  
&nbsp;&nbsp;puts "name: #{element.text}"

&nbsp;&nbsp;if sibling = REXML::XPath.match(element,  
"following-sibling::value").first  
&nbsp;&nbsp;&nbsp;&nbsp;puts sibling.text  
&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;puts "Can't find a \<value\> tag that is a sibling"  
&nbsp;&nbsp;end

&nbsp;&nbsp;puts "-" \* 20  
end

And here is some trickier xml that exercises 'following-sibling::value':

\<?xml version="1.0"?\>  
\<note\>

&nbsp;&nbsp;\<name\>Tove\</name\>  
&nbsp;&nbsp;\<garbage\>xxxx\</garbage\>  
&nbsp;&nbsp;\<value\>Tove's value is: 10\</value\>

&nbsp;&nbsp;\<to\>Tove\</to\>  
&nbsp;&nbsp;\<from\>Jani\</from\>  
&nbsp;&nbsp;\<heading\>Reminder\</heading\>  
&nbsp;&nbsp;\<body\>Don't forget me this weekend!\</body\>

&nbsp;&nbsp;\<parent\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Jani\</name\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<garbage\>xxxx\</garbage\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<garbage\>xxxx\</garbage\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<value\>Jani's value is: 20\</value\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<value\>1200\</value\>  
&nbsp;&nbsp;\</parent\>

&nbsp;&nbsp;\<parent\>  
&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Diane\</name\>  
&nbsp;&nbsp;\</parent\>  
&nbsp;&nbsp;\<value\>Diane's value is: 30\</value\>

\</note\>

--output:--  
name: Tove  
Tove's value is: 10

> **···**
>
> --------------------  
> name: Jani  
> Jani's value is: 20  
> --------------------  
> name: Diane  
> Can't find a \<value\> tag that is a sibling  
> --------------------
> 
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).
