views:

724

answers:

1

I'm implementing an exporter for an XML data format that requires namespaces. I'm using the Nokogiri XML Builder (version 1.4.0) to do this.

However, I can't get Nokogiri to create a root node with a namespace.

This works:

Nokogiri::XML::Builder.new { |xml| xml.root('xmlns:foobar' => 'my-ns-url') }.to_xml

<?xml version="1.0"?>
<root xmlns:foobar="my-ns-url"/>

As does this:

Nokogiri::XML::Builder.new do |xml| 
  xml.root('xmlns:foobar' => 'my-ns-url') { xml['foobar'].child }
end.to_xml

<?xml version="1.0"?>
<root xmlns:foobar="my-ns-url">
  <foobar:child/>
</root>

However, I need something like <foo:root> and this doesn't work:

Nokogiri::XML::Builder.new { |xml| xml['foobar'].root('xmlns:foobar' => 'my-ns-url') }.to_xml

NoMethodError: undefined method `namespace_definitions' for #<Nokogiri::XML::Document:0x11bfef8 name="document">

Namespaces have to be defined before use, apparently, so there's no way to add one to the root node.

I found a question about this on the Nokogiri mailing list, but it had no replies. Anyone have a solution?

+4  A: 
require 'rubygems'
require 'nokogiri'

puts Nokogiri::XML::Builder.new { |xml| 
  xml.root("xmlns:foo"=>"url") {
    xml.parent.namespace = xml.parent.namespace_definitions.first
    xml['foo'].child
  }
}.to_xml

You cannot use xml['foo'] before the namespace is defined, ie before you pass it as an argument to the root not. Thus, the code above add the namespace after-the-fact to the root node.

Adrian
Works like a charm. Thanks!
Luke Francl
You, sir, have spared me much frustration
yalestar
You’re welcome, yalestar.
Adrian