La creación de un documento XML con un elemento raíz de espacio de nombres con el constructor Nokogiri
-
11-09-2019 - |
Pregunta
estoy poniendo en práctica un exportador para un formato de datos XML que requiere espacios de nombres. Estoy usando el XML constructor Nokogiri (versión 1.4.0) para hacer esto.
Sin embargo, no puedo conseguir Nokogiri para crear 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"/>
A medida que 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">
Los espacios de nombres que se han definido antes de su uso, por lo visto, así que no hay manera de añadir uno al nodo raíz.
una pregunta sobre este tema en la lista de correo Nokogiri , pero no tenía ninguna respuesta. Alguien tiene una solución?
Solución
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 se 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 añadir el espacio de nombres después de los hechos al nodo raíz.
Otros consejos
Dos años más tarde, encontré una forma más limpia de hacer esto mediante el uso de referencia del documento de Nokogiri::XML::Builder
para recuperar el nodo raíz y añadir el espacio de nombre (s) a eso. Al igual que la solución anterior, se requiere que el nodo raíz de existir antes de los espacios de nombres pueden ser añadidos a la misma.
He cambiado el elemento <root>
a <rootElement>
así que esto 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 esta mejor, ya que no tiene que buscar el espacio de nombres, y es más fácil añadir varios espacios de nombres.
Tres años después de la respuesta de Lucas, se ha vuelto aún más simple. Ahora puede utilizar el espacio de nombres "antes" se define. 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
Muestra esto XML:
<?xml version="1.0"?>
<foo:RootElement xmlns:foo="bar" xmlns:baz="bat">
<baz:FirstChild/>
</foo:RootElement>