2009-12-01 13 views
11

Estoy implementando un exportador para un formato de datos XML que requiere espacios de nombres. Estoy usando Nokogiri XML Builder (versión 1.4.0) para hacer esto.Creación de un documento XML con un elemento raíz con nombre de espacio con el constructor Nokogiri

Sin embargo, no puedo hacer que Nokogiri cree un nodo raíz con un espacio de nombres.

Esto funciona:

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

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

Como se hace esto:

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> 

Sin embargo, necesito algo así como <foo:root> y esto no funciona:

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"> 

espacios de nombres tienen que ser definido antes del uso, aparentemente, por lo que no hay forma de agregar uno al nodo raíz.

Encontré a question about this on the Nokogiri mailing list, pero no tenía ninguna respuesta. ¿Alguien tiene una solución?

Respuesta

13
require 'rubygems' 
require 'nokogiri' 

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

No puede utilizar xml['foo'] antes de definir el espacio de nombres, es decir, antes de pasarlo como argumento para el nodo raíz. Por lo tanto, el código anterior agrega el espacio de nombres después del hecho al nodo raíz.

+0

funciona como un encanto. ¡Gracias! –

+0

Usted, señor, me ha ahorrado mucha frustración – yalestar

+0

De nada, yalestar. – akuhn

6

Dos años más tarde, encontré una manera más clara de hacerlo utilizando la referencia de documento Nokogiri::XML::Builder para recuperar el nodo raíz y agregar los espacios de nombre a eso. Al igual que la solución anterior, requiere que el nodo raíz exista antes de que se le puedan agregar los espacios de nombres.

He cambiado el elemento <root> a <rootElement> por lo que este es más claro:

builder = Nokogiri::XML::Builder.new do |xml| 
    xml.rootElement do 
    # create a namespace and save it for later 
    ns = xml.doc.root.add_namespace_definition('foo', 'my-ns-url') 
    # you can also create multiple name spaces 
    xml.doc.root.add_namespace_definition('bar', 'http://example.com/bar') 

    # assign the saved namespace to rootElement 
    xml.doc.root.namespace = ns 

    xml['foo'].child 
    xml['bar'].child 
    end 
end 

Ahora, builder.to_xml volverá:

<?xml version="1.0"?> 
<foo:rootElement xmlns:foo="my-ns-url" xmlns:bar="http://example.com/bar"> 
    <foo:child/> 
    <bar:child/> 
</foo:rootElement> 

Me gusta este mejor, ya que no tiene que busque el espacio de nombre, y es más fácil agregar múltiples espacios de nombres.

+0

Esto funciona genial. Gracias. Sin embargo, no puedo deshacerme de la herencia del espacio de nombres. Quiero lograr algo como lo siguiente. valor dknight

0

Tres años después de la respuesta de Luke, es aún más simple. Ahora puede usar el espacio de nombres "antes" de que esté definido. Este código:

require 'nokogiri' 

NAMESPACES = { 'xmlns:foo' => 'bar', 'xmlns:baz' => 'bat' } 

builder = Nokogiri::XML::Builder.new { |xml| 
    xml['foo'].RootElement(NAMESPACES) { 
    xml['baz'].FirstChild 
    } 
} 

puts builder.to_xml 

salidas este XML:

<?xml version="1.0"?> 
<foo:RootElement xmlns:foo="bar" xmlns:baz="bat"> 
    <baz:FirstChild/> 
</foo:RootElement> 
Cuestiones relacionadas