Вот один из способов сделать это.Как отмечено в моем комментарии, «правильный» ответ зависит от того, каким должен быть ваш вывод.В JSON нет канонического представления узлов XML, и, следовательно, в участвующие библиотеки не встроена такая возможность:
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"
]
},
"!"
]
}
]
}
Обратите внимание, что приведенное выше полностью игнорирует пространства имен, которые могут или не могут бытьВы хотите.
Преобразование в JsonML
Вот еще одна альтернатива, которая преобразует в JsonML.Хотя это преобразование с потерями (оно не поддерживает узлы комментариев, DTD или URL-адреса пространств имен), а формат немного «тупой» по своему дизайну (первый дочерний элемент имеет [1]
или [2]
в зависимости от того,атрибуты отсутствуют), указывает префиксы пространства имен для элементов и атрибутов:
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"],"!"]]