Skip to content

Instantly share code, notes, and snippets.

@mccannf
Created October 12, 2012 14:20
Show Gist options
  • Save mccannf/3879418 to your computer and use it in GitHub Desktop.
Save mccannf/3879418 to your computer and use it in GitHub Desktop.
Module to be used with Her ORM to parse XML REST API. Specifically for Redmine REST feed.
module Redmine
class Issue
include Her::Model
end
class ParseXML < Faraday::Response::Middleware
# Parse the response body
#
# @param [String] body The response body
# @return [Mixed] the parsed response
def parse(body) # {{{
xml = Redmine::Hash.from_xml(body)
errors = xml.delete(:errors) || []
metadata = xml.delete(:metadata) || []
{
:data => xml,
:errors => errors,
:metadata => metadata
}
end # }}}
# This method is triggered when the response has been received. It modifies
# the value of `env[:body]`.
#
# @param [Hash] env The response environment
def on_complete(env) # {{{
env[:body] = parse(env[:body])
end # }}}
end
# USAGE: Hash.from_xml:(YOUR_XML_STRING)
# Taken from https://gist.github.com/335286
require 'nokogiri'
# modified from http://stackoverflow.com/questions/1230741/convert-a-nokogiri-document-to-a-ruby-hash/1231297#1231297
class 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.keys.each do |key|
result_hash[:attributes][node.attributes[key].name.to_sym] = prepare(node.attributes[key].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[:attributes]
result_hash['value'] = prepare(result)
return result_hash
else
return prepare(result)
end
end
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
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment