Forked from dimus/Hash.from_xml using Nokogiri
Created
April 17, 2012 23:46
Adding Hash.from_xml method using Nokogiri (properly handle attributtes and Cdata)
This file contains hidden or 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) | |
require 'nokogiri' | |
# modified from http://stackoverflow.com/questions/1230741/convert-a-nokogiri-document-to-a-ruby-hash/1231297#1231297 | |
class NokoHash < Hash | |
class << self | |
def from_xml(xml_io) | |
begin | |
result = Nokogiri::XML(xml_io) | |
return { result.root.name.to_sym => 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 = {} | |
if node.attributes != {} | |
result_hash[:attributes] = {} | |
node.attributes.each do |key, value| | |
result_hash[:attributes][value.name.to_sym] = prepare(value.value) | |
end | |
end | |
if node.children.size > 0 | |
node.children.each do |child| | |
result = xml_node_to_hash(child) | |
if child.name == "text" | |
unless child.next_sibling || child.previous_sibling | |
if !result_hash.empty? | |
result_hash[:value] = prepare(result) | |
return result_hash | |
end | |
return prepare(result) | |
end | |
elsif child.name == "#cdata-section" | |
if !result_hash.empty? | |
result_hash[:value] = prepare(result) | |
return result_hash | |
end | |
return prepare(result) | |
elsif result_hash[child.name.to_sym] | |
if result_hash[child.name.to_sym].is_a?(Object::Array) | |
result_hash[child.name.to_sym] << prepare(result) | |
else | |
result_hash[child.name.to_sym] = [result_hash[child.name.to_sym]] << prepare(result) | |
end | |
else | |
result_hash[child.name.to_sym] = prepare(result) | |
end | |
end | |
return result_hash | |
else | |
return result_hash | |
end | |
else | |
return 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 | |
def to_struct(struct_name) | |
Struct.new(struct_name,*keys).new(*values) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment