Skip to content

Instantly share code, notes, and snippets.

@danlynn
Created May 18, 2009 22:40
Show Gist options
  • Save danlynn/113792 to your computer and use it in GitHub Desktop.
Save danlynn/113792 to your computer and use it in GitHub Desktop.
# XmlObjectParser by Dan Lynn
xml_str = <<XMLEND
<inventory title="OmniCorp Store #45x10^3">
<section name="health">
<item upc="123456789" stock="12">
<name>Invisibility Cream</name>
<price>14.50</price>
<description>Makes you invisible</description>
</item>
<item upc="445322344" stock="18">
<name>Levitation Salve</name>
<price>23.99</price>
<description>Levitate yourself for up to 3 hours per application</description>
</item>
</section>
<section name="food">
<item upc="485672034" stock="653">
<name>Blork and Freen Instameal</name>
<price>4.95</price>
<description>A tasty meal in a tablet; just add water</description>
</item>
<item upc="132957764" stock="44">
<name>Grob winglets</name>
<price>3.56</price>
<description>Tender winglets of Grob. Just add water</description>
</item>
</section>
<to_s>a string</to_s>
</inventory>
XMLEND
# REXML Tutorial = http://www.germane-software.com/software/rexml/docs/tutorial.html
require 'rexml/document'
class XmlObjectParser
retained_methods = %w(__send__ __id__ send class inspect instance_eval instance_variables)
instance_methods.each { |m|
undef_method(m) unless retained_methods.include?(m)
}
def initialize(node, parent_node=nil)
@node = node
@node = REXML::Document.new(node) if node.is_a?(String)
@parent_node = parent_node
end
def method_missing(method, *args)
child_node = @node.elements[method.to_s] || @node.attributes[method.to_s]
return child_node if child_node.is_a?(String)
return child_node.text if !child_node.has_elements?
return XmlObjectParser.new(child_node, @node)
end
def [](*args)
return XmlObjectParser.new(@parent_node.elements[*args], @parent_node) if args[0].is_a?(Fixnum)
return XmlObjectParser.new(@node.elements[*args], @node)
end
end
# my simple version
xml = XmlObjectParser.new(xml_str)
puts xml.inventory.section.name
puts xml.inventory.section.item.stock
puts xml.inventory.section[2].inspect
puts xml.inventory["section/item[@stock='44']"].upc
puts xml.inventory.section.item.name
puts xml.inventory.to_s # note that Object's to_s method has been undefined
# the long REXML version
puts "\n"
doc = REXML::Document.new(xml_str)
puts doc.elements['inventory'].elements['section'].attributes['name']
puts doc.elements['inventory'].elements['section'].elements['item'].attributes['stock']
puts doc.elements['inventory'].elements[2].attributes['name']
puts doc.elements['inventory'].elements["section/item[@stock='44']"].attributes["upc"]
puts doc.elements['inventory'].elements['section'].elements['item'].elements['name'].text
puts doc.elements['inventory'].elements['to_s'].text
# SAMPLE OUTPUT =================
# >> health
# >> 12
# >> #<XmlObjectParser:0x48778 @parent_node=<inventory title='OmniCorp Store #45x10^3'> ... </>, @node=<section name='food'> ... </>>
# >> 132957764
# >> Invisibility Cream
# >> a string
# >>
# >> health
# >> 12
# >> food
# >> 132957764
# >> Invisibility Cream
# >> a string
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment