XML::Mapping and text nodes with attributes

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'})

Tags: , ,

Comments are closed.