While working on an API interface I’ve been playing around with XML::Mapping, an XML-to-object wrapper for ruby. The main reason to use it is that it allows me to easily build an interface similar to that used in Cody Fauser’s Ebay API client which will also be used in the same application.
Generally I’ve been very happy with the library, though at some point it would be nice to have a class generator which will take the XSD file and write most of the code for me, but scour the documentation as I may I couldn’t find an easy way to add attributes to a standard text-holding node. It’s easy enough to get:
<company>
<person id="123">
<name>First Person</name>
</person>
</company>
I couldn’t find a way to get:
<company>
<person id="123">First Person</person>
</company>
without resorting to xpath wrangling.
Thankfully the library allows you to define your own node types, so once I added
module XML
module Mapping
class TextNodeWithAttributes < SingleAttributeNode
def initialize_impl(path)
@path = XML::XXPath.new(path)
end
def extract_attr_value(xml)
default_when_xpath_err{ @path.first(xml).text }
end
def set_attr_value(xml, values)
@path.first(xml, :ensure_created=>true).text = values.delete(:value)
@path.first(xml, :ensure_created=>true).add_attributes(values) unless values.empty?
end
end
end
end
to my code and then included it with
XML::Mapping.add_node_class XML::Mapping::TextNodeWithAttributes
I could specify the above with the class:
module MyNamespace
class Company
text_node_with_attributes :person, 'person'
end
end
and create it with
MyNamespace::Company.new(:person => {:value => 'My Person', 'id' => '123'})