Dave
Dave

Reputation: 666

Parse namespaced xml with ruby nokogiri

I have as second of xml

<Environment
  Name="test"
  xmlns="http://schemas.dmtf.org/ovf/environment/1"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:oe="http://schemas.dmtf.org/ovf/environment/1"
  oe:id="123456789">
  <PropertySection>
      <Property oe:key="mykey" oe:value="test"/>
  </PropertySection>
</Environment>

I'm using ruby and nokogiri to parse the document. i.e.

file = File.open('/tmp/myxml.xml')
doc = Nokogiri::XML(file)

env = doc.at('Environment')
id = env['id']  
printf("ID [%s]\n", id)
properties = env.at('PropertySection')

This works and successfully prints the id from the xml. I now want to access the Property attribute with the key 'mykey'. I tried the following:

value = properties.at('Property[@key="mykey"]')['value']
printf("Value %s\n", value)

Unfortunately the properties.at method returns a nil object. I tried modifying the xml itself to remove the 'oe' namespace from the attribute 'key'. Re-running my script it works.

How can I get nokogiri to recognise the namespace when calling .at() ?

Upvotes: 0

Views: 465

Answers (1)

Jacob Brown
Jacob Brown

Reputation: 7561

You should use the Nokogiri namespace syntax: http://nokogiri.org/tutorials/searching_a_xml_html_document.html#namespaces.

First, make sure you have namespaces you can use:

ns = {
  'xmlns' => 'http://schemas.dmtf.org/ovf/environment/1',
  'oe' => 'http://schemas.dmtf.org/ovf/environment/1'
}

(I'm defining both even though they are the same in this example). You might also look into using the namespaces already available in doc.collect_namespaces.

Then you can just do:

value = properties.at('./xmlns:Property[@oe:key="mykey"]/@oe:value', ns).content

Note that I am using ./ here because, for this specific search, Nokogiri interprets the XPath as CSS without it. You may wish to use .//.

Upvotes: 1

Related Questions