How to Use Xmlns Declarations with Xpath in Nokogiri

How to use xmlns declarations with XPath in Nokogiri

That XPath query looks for elements that are not in any namespace. You need to tell your XPath processor that you are looking for elements in the http://sdb.amazonaws.com/doc/2007-11-07/ namespace.

One way to do that with Nokogiri is:

doc = Nokogiri::XML.parse(...)
doc.xpath("//aws:Item/aws:Attribute[Name='Foo']/aws:Value", {"aws" => "http://sdb.amazonaws.com/doc/2007-11-07/"})

Using nokogiri xpath to access nested elements within an xmlns

It’s a namespacing issue:

datasource.xpath(
'subsystem:connection-url',
'subsystem' => 'urn:jboss:domain:datasources:1.2')
#⇒ [#<... name="connection-url" namespace=...

Nokogiri/Xpath namespace query

All namespaces need to be registered when parsing. Nokogiri automatically registers namespaces on the root node. Any namespaces that are not on the root node you have to register yourself. This should work:

puts doc.xpath('//dc:title', 'dc' => "URI")

Alternately, you can remove namespaces altogether. Only do this if you are certain there will be no conflicting node names.

doc.remove_namespaces!
puts doc.xpath('//title')

Ruby/Nokogiri xmlns and other extensions via xpath

add:cars is an attribute of the price element, not an element itself. The syntax you want is:

root.xpath("//xmlns:price/@add:cars")

or possibly even just

root.xpath("//@add:cars")

if you want the add:cars attributes of all elements.

Note that since the namespaces are declared on the root, Nokogiri registers them automatically so you don’t need to include the mappings in your call to xpath (you will need to include them if your document is more complex with namespaces being declared on non-root elements). Also the default namespace is registered with the prefix xmlns, so you can use that in your XPath.

Nokogiri parse XML with xpath

With method 2, try using:

d.xpath('//feed/entry[title[node()]]'

This will return a nodeset containing nodes that have a non-empty title. Then you can iterate over set however you like.

Xpath - How to navigate to a value (Ruby Nokogiri)


require 'nokogiri'

doc = Nokogiri::XML(File.open("xml4.xml"))
target_date = "2015-02-09"
target_currency = 'USD'

xpaths = [
"//gesmes:Envelope",
"/xmlns:Cube",
"/xmlns:Cube[@time='#{target_date}']",
"/xmlns:Cube[@currency='#{target_currency}']",
]
xpath = xpaths.join

target_cube = doc.at_xpath(xpath)
puts target_cube.attribute('rate')

--output:--
1.1297

Response to comment:

Your root tag:

<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01"
xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">

...declares two namespaces with xmlns, which stands for xml namespace. The namespace:

xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01"

declares that any child tag whose name is prefixed by gesmes, e.g.:

<gesmes:subject>
...
</gesmes:subject>

will actually have a tag name that incorporates the specified url into the tag name, something like this:

<http://www.gesmes.org/xml/2002-08-01:subject>
...
</http://www.gesmes.org/xml/2002-08-01:subject>

The reason you would want to use a namespace is to create a unique name for the Cube tag, so that it doesn't clash with another xml document's Cube tag.

The second namespace declaration:

xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref"

is a default namespace declaration. It declares that any child tag that does not specify a prefix will have the specified url incorporated into its tag name. So a tag like this:

<Cube>
...
</Cube>

becomes something like this:

<http://www.ecb.int/vocabulary/2002-08-01/eurofxref:Cube>
...
</http://www.ecb.int/vocabulary/2002-08-01/eurofxref:Cube>

However, it would be unwieldy to have to write a tag name like that in your xpaths, so in place of the url you instead use the shortcut xmlns:

/xmlns:Cube

XML Namespace issue with Nokogiri

Because Nokogiri requires you to register the XML namespaces you are querying within (read more about XML Namespaces). But you should still be able to query the element if you specify its namespace when calling at_css. To see the exact usage, check out the css method documentation. It should end up looking something like this:

document.at_css "world", 'namespace_name' => 'namespace URI'

Avoiding Nokogiri::XML::XPath::SyntaxError: ERROR: Undefined namespace prefix

I ended up solving the problem by editing the XML file and adding the namespaces in the root. Here is an example:

  temp = Nokogiri::XML(@document_xml)
temp.root['xmlns:w'] = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
@doc = Nokogiri::XML(temp.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML))


Related Topics



Leave a reply



Submit