Katipo
Search  
Site Blog
  About  
  Home
About Portfolio Solutions Client Area Contact Us
: : About Us
Awards
Jobs
Our People
What Is A ... ?
Working From Home
News
Photo Gallery
Katipo Blog


Stupid Human Tricks with Ruby on Rails’ RXML, aka XML Builder

Man, I miss the old “Late Night with David Letterman” of the 80’s sometimes…

Alright, to the point. Ruby on Rails makes it extremely easy to generate nicely formed XML from your application, especially if you are simple doing something like the following:

 def show
    @topic = Topic.find(params[:id])
    respond_to do |format|
      format.html
      format.xml { render :x ml => @topic.to_xml }
    end
  end

If the request is for XML version of the topic, this will take all the attributes of a topic and make them into well formed XML. Nifty, but this doesn’t provide fine-grained control of the XML output which is what I need. RXML templates to the rescue:

def show
    @topic = Topic.find(params[:id])
    respond_to do |format|
      format.html
      format.xml
    end
end

This is deceptively simpler than the previous code. What is implied is that there are two templates for the action named show, one called show.rhtml and the other called show.rxml. What does show.rxml look like? We’ll get to that in a sec. In my case, I want to serve a template with a different name than “show.rxml”. Here’s my show action:

def show
    @topic = Topic.find(params[:id])
    respond_to do |format|
      format.html
      format.xml { render :action => 'oai_record.rxml', :layout => false, :content_type => 'text/xml' }
    end
 end

Not too hard. OAI stands for Open Archives Initiative and essentially is a standard that I want my topic’s XML to adhere to. This standard is a bit trickier than what you normally see as an example of how to use RXML. I thought I would step through how I made it do what I wanted to provide future Rails/RXML explorers some insight.

RXML in RoR uses a Ruby library called Builder (see http://builder.rubyforge.org/ for documentation). It can be extremely simple to use. In your RXML template you are given a magic xml object to operate on, like so:

xml.an_element_name(”the value you want in your element”)

This will result in this being rendered:

<an_element_name>the value you want in your element</an_element_name>

You can also do nested XML tags via blocks:

xml.an_element_name(:an_xml_element_attribute => “attribute value”) do
xml.a_nested_element_name(”nested value”) do
end

Which looks like this:

<an_element_name an_xml_attribute="attribute value" >
    <a_nested_element_name>nested value</a_nested_element_name>
</an_element_name>

This is pretty darn useful in itself. You have element nesting and attributes and you are working in Ruby. Wicked. Builder uses a “method_missing” trick to take what should be a method call on the xml object as what the element name should be.

What if my element name includes a colon to describe a XML namespace? If you take a look at the documentation for Builder you will see that method is interpreted as a ruby symbol by Builder and thus it will blowup. Oh no! Enter the Builder tag! method like so:

xml.tag!(”dc:title”, @topic.title)

This takes the same arguments as the method missing version, but it’s first argument is the name of the element/tag, the second is the value, etc. It also handles element attributes and nesting in the same manner, for example:

xml.tag!("OAI-PMH", "xmlns:xsi".to_sym => "http://www.w3.org/2001/XMLSchema-instance", "xmlns".to_sym => "http://www.openarchives.or\g/OAI/2.0/", "xsi:schemaLocation".to_sym => "http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd") do
    ...
end

Will output this:

<OAI-PMH xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.openarchives.org/OAI/2.0/" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">
    ...
</OAI-PMH>

Notice the “xmlns:xsi”.to_sym? Without the to_sym method, “xmlns:xsi” would be interpreted as a string and thus break ( remember the :symbol_for_attribute_name => “attribute value” syntax?)

What if you want to specify attributes and a value for an element?

xml.request(”value of the element”, :verb => “GetRecord”, :identifier => “oai:some_url:#{@topic.class.name}:#{@topic.id}”, :metadataPrefix => “oai_dc”)

Notice that the value of the element argument comes before anything that is defined with a symbol. The same goes for the tag! version, except it’s positioned over one more to the right. So it would look like this:

xml.tag!(:request, “value of the element”, :verb => “GetRecord”, :identifier => “oai:some_url:#{@topic.class.name}:#{@topic.id}”, :metadataPrefix => “oai_dc”)

Those were the killers for me. I also found xml.instruct! useful for the beginning xml declaration. xml.text! looks handy, too.

Hope this post saves you some time.

Cheers,
Walter

3 Responses to “Stupid Human Tricks with Ruby on Rails’ RXML, aka XML Builder”

  1. walter Says:

    One last thing that I forgot to mention and that I used is the “||” operator for values of the XML elements if the first value isn’t found. For example:

    xml.tag!(”dc:description”, params[:short_summary] || @topic.short_summary)

  2. walter Says:

    Here’s another tutorial about builder:

    http://www.xml.com/pub/a/2006/01/04/creating-xml-with-ruby-and-builder.html

    Cheers,
    Walter

  3. Jason E. Shao » Blog Archive » Ruby, Builder, and CourseManagementXML Data Says:

    [...] Thanks to http://blog.katipo.co.nz/?p=29 for the tips on Builder, especially the bit about using tag! to put in names which would translate to Ruby keywords (e.g. start-date where the – makes it start – date otherwise) [...]

Leave a Reply

You must be logged in to post a comment.


Katipo
Rachel Snowboarding