alex2k8
alex2k8

Reputation: 43214

Ruby XPath to find Attribute

What Ruby library can be used to select attribute using XPath, and to use it as the starting point for other XPath queries.

Example:

<root>
  <add key="A" value="B" />
  <add key="C" value="D" />
  <add foo="E" bar="F" />
</root>

Desired code:

get_pair "//*/@key", "../@value"
get_pair "//*/@foo", "../@bar"

Expected output:

"A" "B"
"C" "D"
"E" "F"

Pseudo implementation:

def get_pair(key, value)
  xml_doc.select[key].each do |a|
    puts [a, a.select[value]]
  end
end

Upvotes: 2

Views: 11929

Answers (5)

vladr
vladr

Reputation: 66681

Your starting point would be REXML

The "challenge" here is how to treat an attribute node as a child node, and this can be done by using singleton methods, then everything else follows naturally:

require "rexml/document"
include REXML  # so that we don't have to prefix everything with REXML::...

def get_pair(xml_doc, key, value)
  XPath.each(xml_doc, key) do |node| 
    if node.is_a?(Attribute)
      def node.parent
        self.element
      end
    end
    puts "\"#{node}\" \"#{XPath.first(node, value)}\""
  end
end

xml_doc = Document.new <<EOF
  <root>
    <add key="A" value="B" />
    <add key="C" value="D" />
    <add foo="E" bar="F" />
  </root>
EOF

get_pair xml_doc, "//*/@key", "../@value"
get_pair xml_doc, "//*/@foo", "../@bar"

produces:

"A" "B"
"C" "D"
"E" "F"

Upvotes: 4

DanSingerman
DanSingerman

Reputation: 36502

Apparently Nokogiri is the fastest Ruby XML parser

See http://www.rubyinside.com/nokogiri-ruby-html-parser-and-xml-parser-1288.html

Was using it today and it's great.

For your example:

doc = Nokogiri::XML(your_xml)
doc.xpath("/root/add").map do |add|
  puts [add['key'], add['value']]
end

Edit: It unsurprisingly turns outthat the claim that Nokogiri is faster is not uncontroversial.

However, we have found it more stable than libxml in our production environmenty (libxml was occasionally crashing; just swapping in Nokogiri has solved the issue)

Upvotes: 3

mletterle
mletterle

Reputation: 3968

rexml, which comes with ruby will do what you want:

require 'rexml/document'
include REXML
xml = Document.new('<root><add key="A" value="B" /><add key="C" value="D" /><add foo="E" bar="F" /></root>')
xml.root.each_element_with_attribute('key'){|e| puts "#{e.attribute('key')} #{e.attribute('value')}"}

Upvotes: 0

Alex Wayne
Alex Wayne

Reputation: 187034

And if you will be parsing a decent amount of data in any area where performance matters, then you will need libxml-ruby. REXML and Hpricot are good, but I recently had to make the switch on my own server for some parsing stuff because it was about 1200% faster.

Upvotes: 1

Toby Hede
Toby Hede

Reputation: 37133

I would also suggest looking at Hpricot ... it is a very expressive HTML and XML parsing library, inspired by jQuery.

Upvotes: 0

Related Questions