Building XML by enumerating through array & hashes data =
[ { 'name' =&gt; 'category1',
    'subCategory' =&gt; [ {'name' =&gt; 'subCategory1',
                        'product' =&gt; [ {'name' =&gt; 'prodcutName1',
                                        'desc' =&gt; 'desc1'},
                                       {'name' =&gt; 'prodcutName2',
                                        'desc' =&gt; 'desc2'}]
                        } ]

  },
  { 
    #category2 ...and so on 
  }
]


Just recently finished a small project with Ruby. I used the above array of hashes to produce a XML.

I think my solution is quite messy nesting loops and builder tags. Can anyone help me out with a more elegant approach? 

builder = Nokogiri::XML::Builder.new { |xml|
data.each { |category| # go through every category in the data array
    xml.category {
        xml.name category['name']
        category['subCategory'].each { |subCategory| # go through each subCategory in the category
            xml.subCategory {
                xml.name subCategory['name']
                subCategory['product'].each { |product| # go though each products and print their data
                    xml.name product['name']
                    xml.desc product['desc']
                }
            }
        }
    }
}


puts builder.to_xml
Here's a nice recursive solution, that creates &lt;key&gt;value&lt;/key&gt; from 'key'=&gt;'value' entries in your hash. If the value is an array, it instead recurses, using the key name as a wrapper element.

require 'nokogiri'

def process_array(label,array,xml)
  array.each do |hash|
    xml.send(label) do                 # Create an element named for the label
      hash.each do |key,value|
        if value.is_a?(Array)
          process_array(key,value,xml) # Recurse
        else
          xml.send(key,value)          # Create &lt;key&gt;value&lt;/key&gt; (using variables)
        end
      end
    end
  end
end

builder = Nokogiri::XML::Builder.new do |xml|
  xml.root do                           # Wrap everything in one element.
    process_array('category',data,xml)  # Start the recursion with a custom name.
  end
end

puts builder.to_xml


When used with this data…

data = [
  { 'name' =&gt; 'category1',
    'subCategory' =&gt; [
      { 'name' =&gt; 'subCategory1',
        'product' =&gt; [
          { 'name' =&gt; 'productName1',
            'desc' =&gt; 'desc1' },
          { 'name' =&gt; 'productName2',
            'desc' =&gt; 'desc2' } ]
      } ]
  },
  { 'name' =&gt; 'category2',
    'subCategory' =&gt; [
      { 'name' =&gt; 'subCategory2.1',
        'product' =&gt; [
          { 'name' =&gt; 'productName2.1.1',
            'desc' =&gt; 'desc1' },
          { 'name' =&gt; 'productName2.1.2',
            'desc' =&gt; 'desc2' } ]
      } ]
  },
]


…you get this result:

&lt;?xml version="1.0"?&gt;
&lt;root&gt;
  &lt;category&gt;
    &lt;name&gt;category1&lt;/name&gt;
    &lt;subCategory&gt;
      &lt;name&gt;subCategory1&lt;/name&gt;
      &lt;product&gt;
        &lt;name&gt;productName1&lt;/name&gt;
        &lt;desc&gt;desc1&lt;/desc&gt;
      &lt;/product&gt;
      &lt;product&gt;
        &lt;name&gt;productName2&lt;/name&gt;
        &lt;desc&gt;desc2&lt;/desc&gt;
      &lt;/product&gt;
    &lt;/subCategory&gt;
  &lt;/category&gt;
  &lt;category&gt;
    &lt;name&gt;category2&lt;/name&gt;
    &lt;subCategory&gt;
      &lt;name&gt;subCategory2.1&lt;/name&gt;
      &lt;product&gt;
        &lt;name&gt;productName2.1.1&lt;/name&gt;
        &lt;desc&gt;desc1&lt;/desc&gt;
      &lt;/product&gt;
      &lt;product&gt;
        &lt;name&gt;productName2.1.2&lt;/name&gt;
        &lt;desc&gt;desc2&lt;/desc&gt;
      &lt;/product&gt;
    &lt;/subCategory&gt;
  &lt;/category&gt;
&lt;/root&gt;




However, if I had control over the XML schema, I'd do this instead:



require 'nokogiri'

def process_array(label,array,xml)
  array.each do |hash|
    kids,attrs = hash.partition{ |k,v| v.is_a?(Array) }
    xml.send(label,Hash[attrs]) do
      kids.each{ |k,v| process_array(k,v,xml) }
    end
  end
end

builder = Nokogiri::XML::Builder.new do |xml|
  xml.root{ process_array('category',data,xml) }
end

puts builder.to_xml




&lt;?xml version="1.0"?&gt;
&lt;root&gt;
  &lt;category name="category1"&gt;
    &lt;subCategory name="subCategory1"&gt;
      &lt;product name="productName1" desc="desc1"/&gt;
      &lt;product name="productName2" desc="desc2"/&gt;
    &lt;/subCategory&gt;
  &lt;/category&gt;
  &lt;category name="category2"&gt;
    &lt;subCategory name="subCategory2.1"&gt;
      &lt;product name="productName2.1.1" desc="desc1"/&gt;
      &lt;product name="productName2.1.2" desc="desc2"/&gt;
    &lt;/subCategory&gt;
  &lt;/category&gt;
&lt;/root&gt;


…but perhaps you're dealing with some terrible XML schema like PList.