Come for the quick hacks, stay for the epiphanies. | |
PerlMonks |
Embedding a mini-language for XML construction into Perlby tmoertel (Chaplain) |
on Nov 18, 2005 at 23:46 UTC ( [id://510000]=perlmeditation: print w/replies, xml ) | Need Help?? |
In this meditation, we will embed a mini-language for building XML
documents into Perl. Our goal is to see how much syntax we can remove
in pursuit of what Damian Conway calls "sufficiently
advanced technologies." We want to make building XML just like
writing native Perl:
There is nothing particularly novel about this approach, and there are similar libraries for many programming languages. Our implementation, however, will stress Perlishness and simplicity. To eliminate clutter during the meditation, we will not make a module but instead expose the underlying code. Here is our game plan. We will represent XML documents as trees of nested arrays and then render the trees as XML. A node in our tree will be either text (represented as a string) or an element (represented as a triple of the form [name, attributes, children_nodes]). Attributes will be pairs of the form [name, value]. (We will ignore namespaces, XML declarations, and other aspects of XML generation that don't add much to the meditation.) To build a document, we will call functions that append elements, attributes, and text to the active node in the tree, redefining the active node in passing:
To make it all seem more natural, we will use the (&) prototype on element-creating functions and doc. This lets us use braces to represent nesting when calling the functions:
Likewise, the attribute-creating functions and text get the ($) prototype. This lets us call them without having to use parentheses:
With the game plan in mind, let's work top down: The functions _elem and _attr are helpers used by the following function, which lets us embed a custom XML vocabulary into Perl by creating the appropriate Perl functions for the vocabulary's elements and attributes: We can use the above function, for example, to embed a subset of XHTML into Perl: (The use of BEGIN ensures that the embedded functions' prototypes are established before any remaining code is compiled.) Let's try out our newly embedded vocabulary by dumping out the internal representation of a simple document:
Good! That's just what we want. All that is left for us to do is render the internal representation as XML. The simplicity of our internal representation makes this straightforward. Here's a renderer for XML::Writer:Now we can render our earlier document: In most cases we will render documents shortly after creating them. We can "huffmanize" this common case with another helper, which supplies the outer doc for us and then renders the resulting tree: Our final example shows the fruits of our labors. We have successfully embedded a custom subset of XHTML into Perl. Now we can use it to create XML fragments with very little syntactic overhead. Further, because our embedding is "just Perl," we can freely mix code and fragments to do the work of template engines: Thanks for taking the time to read this meditation! If you find anything about it unclear, or can think of a way to improve my writing, please let me know. Cheers Tom Moertel : Blog / Talks / CPAN / LectroTest / PXSL / Coffee / Movie Rating Decoder
Back to
Meditations
|
|