ROXML Ruby Object to XML mapping library. For more information visit roxml.rubyforge.org

Quick Start Guide

This is a short usage example. See ROXML::ClassMethods::Declarations and packaged test cases for more information.

Basic Mapping

Consider an XML document representing a Library containing a number of Books. You can map this structure to Ruby classes that provide addition useful behavior. With ROXML, you can annotate the Ruby classes as follows:

class Book
  include ROXML

  xml_reader :isbn, :attr => "ISBN" # attribute with name 'ISBN'
  xml_reader :title
  xml_reader :description, :as => :cdata  # text node with cdata protection
  xml_reader :author
end

class Library
  include ROXML

  xml_accessor :name, :from => "NAME", :as => :cdata
  xml_accessor :books, [Book], :in => "books"
end

To create a library and put a number of books in it we could run the following code:

book = Book.new()
book.isbn = "0201710897"
book.title = "The PickAxe"
book.description = "Best Ruby book out there!"
book.author = "David Thomas, Andrew Hunt, Dave Thomas"

lib = Library.new()
lib.name = "Favorite Books"
lib << book

To save this information to an XML file:

File.open("library.xml", "w") do |f|
  lib.to_xml.write(f, 0)
end

To later populate the library object from the XML file:

lib = Library.from_xml(File.read("library.xml"))

Similarly, to do a one-to-one mapping between XML objects, such as book and publisher, you would add a reference to another ROXML class. For example:

<book isbn="0974514055">
  <title>Programming Ruby - 2nd Edition</title>
  <description>Second edition of the great book.</description>
  <publisher>
    <name>Pragmatic Bookshelf</name>
  </publisher>
</book>

can be mapped using the following code:

class BookWithPublisher
  include ROXML

  xml_name :book
  xml_reader :publisher, Publisher
end

Note: In the above example, xml_name annotation tells ROXML to set the element name to “book” for mapping to XML. The default is XML element name is the class name in lowercase; “bookwithpublisher” in this case.

Manipulation

Extending the above examples, say you want to parse a book’s page count and have it available as an Integer. In such a case, you can extend any object with a block to manipulate it’s value at parse time. For example:

class Child
  include ROXML

  xml_reader :age, :attr do |val|
    Integer(val)
  end
end

The result of the block above is stored, rather than the actual value parsed from the document.

Construction

Complicated initialization may require action on multiple attributes of an object. As such, you can define method xml_initialize to perform initialization after instantiation and parsing, including causing your ROXML object to call its own constructor, as in the following:

class Measurement
  include ROXML

  xml_reader :units, :attr
  xml_reader :value, :content

  def xml_initialize
    # xml attributes of self are already valid
    initialize(value, units)
  end

  def initialize(value, units)
    # translate units & value into metric, for example
  end
end

One important use of this approach is to make ROXML object which may or may not include an xml backing, which may be used via new construction as well as from_xml construction.

Selecting a parser

By default, ROXML will use LibXML if it is available, or otherwise REXML. If you’d like to explicitly require one or the other, you may do the following:

module ROXML
  XML_PARSER = 'libxml' # or 'rexml'
end
require 'roxml'

For more information on available annotations, see ROXML::ClassMethods::Declarations