La creación de un documento XML con un elemento raíz de espacio de nombres con el constructor Nokogiri

StackOverflow https://stackoverflow.com/questions/1829425

  •  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?

¿Fue útil?

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>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top