Announcing XMLegant for PHP
Update: I've also written a Python version of XMLegant
While SimpleXML has made reading XML relatively painless, no analogous tool exists for generating XML from scratch. To fill this need, I've created XMLegant (github, download latest as zip).
To see how XMLegant works, let's take a simple example. Suppose we want to generate the following document:
<books>
<book>
<title>Title 1</title>
<author>Author 1</author>
<isbn>isbn 1</isbn>
</book>
<book>
<title>Title 2</title>
<author>Author 2</author>
<isbn>isbn 2</isbn>
</book>
<book>
<title>Title 3</title>
<author>Author 3</author>
<isbn>isbn 3</isbn>
</book>
</books>
We can use the following code:
$x = new XMLegant();
for($i=0;$i<5;$i++)
$x->books->book()->title("Title $i")
->author("Author $i")
->isbn("isbn $i");
echo $x->toXML();
And to generate this document:
<a>
<b>c</b>
<b>d</b>
<e>f</e>
<b>g</b>
<h>
<i j="k"/>
<l>
<m/>
</l>
<n>o</n>
</h>
<a>
We can use either:
$x = new XMLegant(); $x->a->b = 'c'; $x->a->b[] = 'd'; $x->a->e = 'f'; $x->a->b[] = 'g'; $x->a->h->i['j'] = 'k'; $x->a->h->l->m; $x->a->h->n = 'o';
or:
$x = new XMLegant();
$x->a()
->b('c')
->b('d')
->e('f')
->b('g')
->h()
->i('j', 'k')
->l()
->m('')
->getParent()
->n('o');
How does this work?
XMLegant uses PHP's overloading and the SPL ArrayAccess interface. This allows interception of calls to unnamed functions or member variables as well as subscript access to the object. Using this, we can construct an XML access through manipulation of these anonymous calls.
Take this code:
$x = new XMLegant(); $x->a->b->c->d = 'e'; $x->a->b['f'] = 'g'; $x->toXML();
Which produces this:
<a>
<b f="g">
<c>
<d>e</d>
</c>
</b>
</a>
This code first starts with the root object $x.
$x->ais called, which looks for the most recently createdachild. Since none exists, anaelement is created and added as a child of$x.->bis called, which looks for the most recently createdbchild ofa. Since none exists, abelement is created and added as a child ofa.->cis called, which looks for the most recently createdcchild ofb. Since none exists, acelement is created and added as a child ofb.->dis called, which looks for the most recently createddchild ofc. Since none exists, adelement is created and added as a child ofc.d = 'e'is called, which assigns'e'as a text node ofd.
The second line finds the already created a element, finds the already created b child of a, and then sets the attribute f of b to 'g'.
Many more examples are available in demo.php. Also, XMLegant_Tests.php consists of a number of unit tests that may be useful as a guide.