ruby - parse - Cómo convertir el documento de Nokogiri en JSON
nokogiri parse xml (2)
Aquí hay una forma de hacerlo. Como he señalado en mi comentario, la respuesta ''correcta'' depende de lo que debería ser su salida. No hay una representación canónica de nodos XML en JSON y, por lo tanto, no existe tal capacidad incorporada en las bibliotecas involucradas:
require ''nokogiri''
require ''json''
class Nokogiri::XML::Node
def to_json(*a)
{"$name"=>name}.tap do |h|
kids = children.to_a
h.merge!(attributes)
h.merge!("$text"=>text) unless text.empty?
h.merge!("$kids"=>kids) unless kids.empty?
end.to_json(*a)
end
end
class Nokogiri::XML::Document
def to_json(*a); root.to_json(*a); end
end
class Nokogiri::XML::Text
def to_json(*a); text.to_json(*a); end
end
class Nokogiri::XML::Attr
def to_json(*a); value.to_json(*a); end
end
xml = Nokogiri::XML ''<root a="b" xmlns:z="zzz">
<z:a>Hello <b z:x="y">World</b>!</z:a>
</root>''
puts xml.to_json
{
"$name":"root",
"a":"b",
"$text":"Hello World!",
"$kids":[
{
"$name":"a",
"$text":"Hello World!",
"$kids":[
"Hello ",
{
"$name":"b",
"x":"y",
"$text":"World",
"$kids":[
"World"
]
},
"!"
]
}
]
}
Tenga en cuenta que lo anterior ignora completamente los espacios de nombres, que pueden o no ser lo que usted desea.
Convertir a JsonML
Aquí hay otra alternativa que se convierte a JsonML. Si bien esta es una conversión con pérdida (no admite nodos de comentarios, DTD o URL de espacio de nombres) y el formato es un poco "torpe" por diseño (el primer elemento secundario está en [1]
o [2]
dependiendo de si o no hay atributos presentes), indica prefijos de espacio de nombres para elementos y atributos:
require ''nokogiri''
require ''json''
class Nokogiri::XML::Node
def namespaced_name
"#{namespace && "#{namespace.prefix}:"}#{name}"
end
end
class Nokogiri::XML::Element
def to_json(*a)
[namespaced_name].tap do |parts|
unless attributes.empty?
parts << Hash[ attribute_nodes.map{ |a| [a.namespaced_name,a.value] } ]
end
parts.concat(children.select{|n| n.text? ? (n.text=~//S/) : n.element? })
end.to_json(*a)
end
end
class Nokogiri::XML::Document
def to_json(*a); root.to_json(*a); end
end
class Nokogiri::XML::Text
def to_json(*a); text.to_json(*a); end
end
class Nokogiri::XML::Attr
def to_json(*a); value.to_json(*a); end
end
xml = Nokogiri::XML ''<root a="b" xmlns:z="zzz">
<z:a>Hello <b z:x="y">World</b>!</z:a>
</root>''
puts xml.to_json
#=> ["root",{"a":"b"},["z:a","Hello ",["b",{"z:x":"y"},"World"],"!"]]
He analizado algunos objetos Nokogiri::XML::Document
que deseo imprimir como JSON.
Puedo seguir la ruta para convertirla en una cadena, analizarla en un hash, con registro activo o Crack y luego Hash.to_json; pero eso es a la vez feo y dependiendo de muchas bibliotecas.
¿No hay una forma más sencilla?
Según la solicitud en el comentario, por ejemplo, el XML <root a="b"><a>b</a></root>
podría representarse como JSON:
<root a="b"><a>b</a></root> #=> {"root":{"a":"b"}}
<root foo="bar"><a>b</a></root> #=> {"root":{"a":"b","foo":"bar"}}
Eso es lo que consigo con Crack ahora también. Y, claro, las colisiones entre entidades y etiquetas de niños son un problema potencial, pero yo mismo construyo la mayoría del XML, por lo que es más fácil para mí evitar estas colisiones por completo :)
Esta funciona para mí:
Hash.from_xml(@nokogiri_object.to_xml).to_json
Este método utiliza el soporte activo, por lo tanto, si no está usando rieles, incluya las extensiones del núcleo de soporte activo manualmente:
require ''active_support/core_ext/hash''