Here's a nice recursive solution, that creates <key>value</key>
from 'key'=>'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 <key>value</key> (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' => 'category1',
'subCategory' => [
{ 'name' => 'subCategory1',
'product' => [
{ 'name' => 'productName1',
'desc' => 'desc1' },
{ 'name' => 'productName2',
'desc' => 'desc2' } ]
} ]
},
{ 'name' => 'category2',
'subCategory' => [
{ 'name' => 'subCategory2.1',
'product' => [
{ 'name' => 'productName2.1.1',
'desc' => 'desc1' },
{ 'name' => 'productName2.1.2',
'desc' => 'desc2' } ]
} ]
},
]
…you get this result:
<?xml version="1.0"?>
<root>
<category>
<name>category1</name>
<subCategory>
<name>subCategory1</name>
<product>
<name>productName1</name>
<desc>desc1</desc>
</product>
<product>
<name>productName2</name>
<desc>desc2</desc>
</product>
</subCategory>
</category>
<category>
<name>category2</name>
<subCategory>
<name>subCategory2.1</name>
<product>
<name>productName2.1.1</name>
<desc>desc1</desc>
</product>
<product>
<name>productName2.1.2</name>
<desc>desc2</desc>
</product>
</subCategory>
</category>
</root>
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
<?xml version="1.0"?>
<root>
<category name="category1">
<subCategory name="subCategory1">
<product name="productName1" desc="desc1"/>
<product name="productName2" desc="desc2"/>
</subCategory>
</category>
<category name="category2">
<subCategory name="subCategory2.1">
<product name="productName2.1.1" desc="desc1"/>
<product name="productName2.1.2" desc="desc2"/>
</subCategory>
</category>
</root>
…but perhaps you're dealing with some terrible XML schema like PList.