-
-
Save baroquebobcat/1603671 to your computer and use it in GitHub Desktop.
Adding Hash.from_xml method using Nokogiri
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# USAGE: Hash.from_xml:(YOUR_XML_STRING) | |
# | |
# - fixes handling of <text> elements | |
# - prepends namespaces on keys where used including both elements & attributes | |
# - uses strings instead of symbols to prevent consumption of the symbol table | |
require 'nokogiri' | |
# modified from http://stackoverflow.com/questions/1230741/convert-a-nokogiri-document-to-a-ruby-hash/1231297#1231297 | |
class Nokogiri::XML::Node | |
def namespaced_name | |
(namespace ? "#{namespace.prefix}:" : "") + name | |
end | |
end | |
class Hash | |
class << self | |
def from_xml(xml_io) | |
begin | |
result = Nokogiri::XML(xml_io) | |
return { result.root.name => xml_node_to_hash(result.root)} | |
rescue Exception => e | |
# raise your custom exception here | |
end | |
end | |
def xml_node_to_hash(node) | |
# If we are at the root of the document, start the hash | |
if node.element? | |
result_hash = {} | |
result_hash['attributes'] = {} unless node.attributes.empty? | |
node.attributes.each do |key, attr| | |
result_hash['attributes'][attr.namespaced_name] = prepare(attr.value) | |
end | |
node.children.each do |child| | |
result = xml_node_to_hash(child) | |
if child.is_a? Nokogiri::XML::Text | |
unless child.next_sibling || child.previous_sibling | |
return prepare(result) | |
end | |
elsif result_hash[child_name = child.namespaced_name] | |
result_hash[child_name] = [result_hash[child_name]] unless result_hash[child_name].is_a?(Object::Array) | |
result_hash[child_name] << prepare(result) | |
else | |
result_hash[child_name] = prepare(result) | |
end | |
end | |
result_hash | |
else | |
prepare(node.content.to_s) | |
end | |
end | |
def prepare(data) | |
(data.class == String && data.to_i.to_s == data) ? data.to_i : data | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment