XML

Although JSON has become perhaps the most common serialization format—in certain circles, anyway—that’s not been wholly at the expense of XML. Many APIs still return it and expect it as input; many applications use it for configuration and storage. At some point, you will definitely need to write XML.

XML as a Tree

XML is fundamentally a representation of a tree. There is a root node, which has children, which may also have children, and so on down a hierarchy of arbitrary depth.

If we represented information about a car, for example, we might end up with XML that looks like this:

 
<car>
 
<make>Ford</make>
 
<model>Model T</model>
 
<engine>
 
<size>2.9 L</size>
 
<power>20 hp</power>
 
</engine>
 
</car>

Our root node is car, representing a car. A car node has three children, each representing a different attribute of the car: its make, its model, and its engine. Within the engine element we have further children, representing the properties the engine has—in this case, its size and power.

Building a Tree

Building such a nested tree in Ruby is straightforward, especially if you utilize the late Jim Weirich’s wonderful library Builder.[15]

Builder is a domain-specific language (DSL) for building XML. Thanks to Ruby’s flexible syntax and to Jim Weirich’s enormous creativity, it allows you to write code like this:

builder-example.rb
 
require ​"builder"
 
 
builder = Builder::XmlMarkup.new(​:indent​ => 2)
 
 
xml = builder.car ​do​ |car|
 
car.make ​"Ford"
 
car.model ​"Model T"
 
car.engine ​do​ |engine|
 
engine.size ​"2.9 L"
 
engine.power ​"20 hp"
 
end
 
end

When we output xml, implicitly converting it to a string, we see that all of the XML has been generated for us:

builder-example.rb
 
puts xml
 
# >> <car>
 
# >> <make>Ford</make>
 
# >> <model>Model T</model>
 
# >> <engine>
 
# >> <size>2.9 L</size>
 
# >> <power>20 hp</power>
 
# >> </engine>
 
# >> </car>

Thanks to the indent option that we passed when setting up the builder object, it’s even generated “pretty” output for us, indented correctly according to the nesting of the document.

It looks a lot like magic, but it’s not. The object returned from Builder::XmlMarkup.new, that we assigned to builder, is a special one. It has no methods of its own, but instead responds to any message passed to it (in this case, things like car, make, model, and so on). When these methods are called, a new element is introduced into the document. If a block has been passed to the method, the block is executed with the builder passed as an argument, so that the block can add elements below the current one.

This simple concept underpins the entirety of Builder and is what makes it feel so natural. Read through the code, and it feels like we’ve described, in plain English, the attributes of the car. It doesn’t feel like we’re constructing XML at all.

So far we’ve just looked at creating new elements. But a key part of XML is attributes—modifiers on elements, such as:

 
<painting name=​"Anna and the Blind Tobit"​ artist=​"Rembrandt"​ year=​"1630"​/>

Let’s imagine we wanted a whole gallery of such paintings, each with those particular attributes. Let’s see if we can do this while maintaining the readability of the first example:

builder-attributes.rb
 
require ​"builder"
 
 
builder = Builder::XmlMarkup.new(​:indent​ => 2)
 
 
xml = builder.gallery ​do​ |gallery|
 
gallery.name ​"The National Gallery"
 
gallery.location ​"London, UK"
 
 
gallery.collection ​do​ |collection|
 
collection.painting(
 
name: ​​"Anna and the Blind Tobit"​,
 
artist: ​​"Rembrandt"​,
 
year: ​1630
 
)
 
 
collection.painting(
 
name: ​​"The Stonemason's Yard"​,
 
artist: ​​"Canaletto"​,
 
year: ​1725
 
)
 
end
 
end
 
 
puts xml
 
# >> <gallery>
 
# >> <name>The National Gallery</name>
 
# >> <location>London, UK</location>
 
# >> <collection>
 
# >> <painting name="Anna and the Blind Tobit" artist="Rembrandt" year="1630"/>
 
# >> <painting name="The Stonemason's Yard" artist="Canaletto" year="1725"/>
 
# >> </collection>
 
# >> </gallery>

This maintains all the readability of the first example. It flows naturally, and the difference between attributes and new elements is tangible without one being more clumsy than the other.

That’s about all there is to the core of Builder’s functionality, and yet with it we can construct even the most complex of documents. Whatever your thoughts on XML, generating it in Ruby should never be painful and can even be fun.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.191.195