# \[ANN\] xml-mapping 0.8

**URL:** <https://rubytalk.org/t/ann-xml-mapping-0-8/19387>\
**Category:** ruby-talk\
**Created:** [7 July 2005 05:30 UTC](https://rubytalk.org/t/ann-xml-mapping-0-8/19387 "2005-07-07T05:30:47Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Olaf\_Klischat1](https://avatars.discourse-cdn.com/v4/letter/o/9e8a1a/32.png) [@Olaf\_Klischat1](https://rubytalk.org/u/Olaf_Klischat1)\
**Post date:** [7 July 2005 05:30 UTC](https://rubytalk.org/t/ann-xml-mapping-0-8/19387/1 "2005-07-07T05:30:47Z")

</div>

Project Homepage: [http://xml-mapping.rubyforge.org/](http://xml-mapping.rubyforge.org/)  
Download, CVS etc.: [http://rubyforge.org/projects/xml-mapping](http://rubyforge.org/projects/xml-mapping)

xml-mapping is an easy to use, extensible library for mapping Ruby  
objects to XML trees and back. It includes an XPath interpreter (see  
below).

> **···**
>
> ===========================  
> Example:
> 
> ----------------------------  
> Input document:  
> ----------------------------  
> (example document stolen + extended from  
> [www.castor.org/xml-mapping.html](http://www.castor.org/xml-mapping.html))
> 
> \<?xml version="1.0" encoding="ISO-8859-1"?\>
> 
> \<order reference="12343-AHSHE-314159"\>  
> &nbsp;&nbsp;\<client\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<name\>Jean Smith\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<address where="home"\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<city\>San Mateo\</city\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<state\>CA\</state\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<zip\>94403\</zip\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<street\>2000, Alameda de las Pulgas\</street\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\</address\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<address where="work"\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<city\>San Francisco\</city\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<state\>CA\</state\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<zip\>94102\</zip\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<street\>98765, Fulton street\</street\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\</address\>  
> &nbsp;&nbsp;\</client\>
> 
> &nbsp;&nbsp;\<item reference="RF-0001"\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<description\>Stuffed Penguin\</description\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<quantity\>10\</quantity\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<unit-price\>8.95\</unit-price\>  
> &nbsp;&nbsp;\</item\>
> 
> &nbsp;&nbsp;\<item reference="RF-0034"\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<description\>Chocolate\</description\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<quantity\>5\</quantity\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<unit-price\>28.50\</unit-price\>  
> &nbsp;&nbsp;\</item\>
> 
> &nbsp;&nbsp;\<item reference="RF-3341"\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<description\>Cookie\</description\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<quantity\>30\</quantity\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<unit-price\>0.85\</unit-price\>  
> &nbsp;&nbsp;\</item\>
> 
> &nbsp;&nbsp;\<signed-by\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\<signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>John Doe\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<position\>product manager\</position\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\</signature\>
> 
> &nbsp;&nbsp;&nbsp;&nbsp;\<signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Jill Smith\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<position\>clerk\</position\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\</signature\>
> 
> &nbsp;&nbsp;&nbsp;&nbsp;\<signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Miles O'Brien\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\</signature\>  
> &nbsp;&nbsp;\</signed-by\>
> 
> \</order\>
> 
> ----------------------------  
> Mapping class declarations:  
> ----------------------------
> 
> require 'xml/mapping'
> 
> ## forward declarations  
> class Client; end  
> class Address; end  
> class Item; end  
> class Signature; end
> 
> class Order  
> &nbsp;&nbsp;include XML::Mapping
> 
> &nbsp;&nbsp;text\_node :reference, "@reference"  
> &nbsp;&nbsp;object\_node :client, "client", :class=\>Client  
> &nbsp;&nbsp;hash\_node :items, "item", "@reference", :class=\>Item  
> &nbsp;&nbsp;array\_node :signatures, "signed-by", "signature", :class=\>Signature, :default\_value=\>[]
> 
> &nbsp;&nbsp;def total\_price  
> &nbsp;&nbsp;&nbsp;&nbsp;items.values.map{|i| i.total\_price}.inject(0){|x,y|x+y}  
> &nbsp;&nbsp;end  
> end
> 
> class Client  
> &nbsp;&nbsp;include XML::Mapping
> 
> &nbsp;&nbsp;text\_node :name, "name"  
> &nbsp;&nbsp;object\_node :home\_address, "address[@where='home']", :class=\>Address  
> &nbsp;&nbsp;object\_node :work\_address, "address[@where='work']", :class=\>Address, :default\_value=\>nil  
> end
> 
> class Address  
> &nbsp;&nbsp;include XML::Mapping
> 
> &nbsp;&nbsp;text\_node :city, "city"  
> &nbsp;&nbsp;text\_node :state, "state"  
> &nbsp;&nbsp;numeric\_node :zip, "zip"  
> &nbsp;&nbsp;text\_node :street, "street"  
> end
> 
> class Item  
> &nbsp;&nbsp;include XML::Mapping
> 
> &nbsp;&nbsp;text\_node :descr, "description"  
> &nbsp;&nbsp;numeric\_node :quantity, "quantity"  
> &nbsp;&nbsp;numeric\_node :unit\_price, "unit-price"
> 
> &nbsp;&nbsp;def total\_price  
> &nbsp;&nbsp;&nbsp;&nbsp;quantity\*unit\_price  
> &nbsp;&nbsp;end  
> end
> 
> class Signature  
> &nbsp;&nbsp;include XML::Mapping
> 
> &nbsp;&nbsp;text\_node :name, "name"  
> &nbsp;&nbsp;text\_node :position, "position", :default\_value=\>"Some Employee"  
> end
> 
> ----------------------------  
> Usage  
> ----------------------------
> 
> ####read access  
> o=Order.load\_from\_file("order.xml")  
> =\> #\<Order:0x40461390 @signatures=[#\<Signature[....] @reference="12343-AHSHE-314159"\>  
> o.reference  
> =\> "12343-AHSHE-314159"  
> o.client  
> =\> #\<Client:0x404609e0 @name="Jean Smith", @work\_address=#\<Address:0x4045de5c @city="San Francisco", @street="98765, Fulton street", @zip=94102, @state="CA"\>, @home\_address=#\<Address:0x4045fd10 @city="San Mateo", @street="2000, Alameda de las Pulgas", @zip=94403, @state="CA"\>\>  
> o.items.keys  
> =\> ["RF-3341", "RF-0034", "RF-0001"]  
> o.items["RF-0034"].descr  
> =\> "Chocolate"  
> o.items["RF-0034"].total\_price  
> =\> 142.5  
> o.signatures  
> =\> [#\<Signature:0x40456f30 @name="John Doe", @position="product manager"\>, #\<Signature:0x40456314 @name="Jill Smith", @position="clerk"\>, #\<Signature:0x404556f8 @name="Miles O'Brien", @position="Some Employee"\>]  
> o.signatures[2].name  
> =\> "Miles O'Brien"  
> o.signatures[2].position  
> =\> "Some Employee"  
> ## default value was set
> 
> o.total\_price  
> =\> 257.5
> 
> ####write access  
> o.client.name="James T. Kirk"  
> o.items['RF-4711'] = Item.new  
> o.items['RF-4711'].descr = 'power transfer grid'  
> o.items['RF-4711'].quantity = 2  
> o.items['RF-4711'].unit\_price = 29.95
> 
> s=Signature.new  
> s.name='Harry Smith'  
> s.position='general manager'  
> o.signatures \<\< s  
> xml=o.save\_to\_xml #convert to REXML node; there's also o.save\_to\_file(name)  
> =\> \<order reference='12343-AHSHE-314159'\> ... \</\>  
> xml.write($stdout,2)  
> \<order reference='12343-AHSHE-314159'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<client\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>James T. Kirk\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<address where='home'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<city\>San Mateo\</city\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<state\>CA\</state\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<zip\>94403\</zip\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<street\>2000, Alameda de las Pulgas\</street\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</address\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<address where='work'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<city\>San Francisco\</city\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<state\>CA\</state\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<zip\>94102\</zip\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<street\>98765, Fulton street\</street\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</address\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</client\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<item reference='RF-3341'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<description\>Cookie\</description\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<quantity\>30\</quantity\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<unit-price\>0.85\</unit-price\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</item\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<item reference='RF-0034'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<description\>Chocolate\</description\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<quantity\>5\</quantity\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<unit-price\>28.5\</unit-price\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</item\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<item reference='RF-0001'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<description\>Stuffed Penguin\</description\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<quantity\>10\</quantity\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<unit-price\>8.95\</unit-price\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</item\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<item reference='RF-4711'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<description\>power transfer grid\</description\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<quantity\>2\</quantity\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<unit-price\>29.95\</unit-price\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</item\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<signed-by\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>John Doe\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<position\>product manager\</position\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Jill Smith\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<position\>clerk\</position\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Miles O&apos;Brien\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Harry Smith\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<position\>general manager\</position\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</signature\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</signed-by\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\</order\>
> 
> ####Starting a new order from scratch  
> o = Order.new  
> =\> #\<Order:0x4043c9f0 @signatures=[]\>  
> ## attributes with default values (here: signatures) are set  
> ## automatically
> 
> xml=o.save\_to\_xml  
> XML::MappingError: no value, and no default value, for attribute: reference  
> &nbsp;&nbsp;from ../../lib/xml/../xml/mapping/base.rb:377:in `obj\_to\_xml'  
> &nbsp;&nbsp;from ../../lib/xml/../xml/mapping/base.rb:157:in `fill\_into\_xml'  
> &nbsp;&nbsp;from ../../lib/xml/../xml/mapping/base.rb:156:in `each'  
> &nbsp;&nbsp;from ../../lib/xml/../xml/mapping/base.rb:156:in `fill\_into\_xml'  
> &nbsp;&nbsp;from ../../lib/xml/../xml/mapping/base.rb:168:in `save\_to\_xml'  
> ## can't save as long as there are still unset attributes without  
> ## default values
> 
> o.reference = "FOOBAR-1234"
> 
> o.client = Client.new  
> [o.client.name](http://o.client.name) = 'Ford Prefect'  
> o.client.home\_address = Address.new  
> o.client.home\_address.street = '42 Park Av.'  
> o.client.home\_address.city = 'small planet'  
> o.client.home\_address.zip = 17263  
> o.client.home\_address.state = 'Betelgeuse system'
> 
> o.items={'XY-42' =\> Item.new}  
> o.items['XY-42'].descr = 'improbability drive'  
> o.items['XY-42'].quantity = 3  
> o.items['XY-42'].unit\_price = 299.95
> 
> o.save\_to\_xml.write($stdout,2)
> 
> \<order reference='FOOBAR-1234'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<client\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<name\>Ford Prefect\</name\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<address where='home'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<city\>small planet\</city\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<state\>Betelgeuse system\</state\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<zip\>17263\</zip\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<street\>42 Park Av.\</street\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</address\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</client\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<item reference='XY-42'\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<description\>improbability drive\</description\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<quantity\>3\</quantity\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<unit-price\>299.95\</unit-price\>  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\</item\>  
> &nbsp;&nbsp;&nbsp;&nbsp;\</order\>  
> ## the root element name when saving an object to XML will by default  
> ## be derived from the class name (in this example, "Order" became  
> ## "order"). This can be overridden on a per-class basis; see  
> ## XML::Mapping::ClassMethods#root\_element\_namefor details.
> 
> =======
> 
> As shown in the example, you generally include XML::Mapping in a class  
> to turn it into a "mapping class", and then map instance attributes to  
> XML sub-trees at will. XPath expressions like "@reference",  
> "signed-by", or "address[@where='home']" in the mapping class  
> definition locate the sub-trees; an XPath interpreter is bundled with  
> xml-mapping for reading and writing data from/to them.
> 
> The XPath interpreter can also be used on its own; it does not depend  
> on the rest of the library.
> 
> Several "node types" like text\_node, numeric\_node, array\_node etc. are  
> provided; it is easy to write your own ones and register them with the  
> xml-mapping library. There is even documentation on all this :)=
> 
> Olaf
