How to generate XML in PHP (in a painless way)
I have always avoided working with XML. Parsing and writing it always felt too difficult. I thought that way until I found an actually easy and manageable way of working with it. I will focus on the process of generating XML documents using PHP.
As many developers out there, I started using fixed templates with placeholders. The following example will look familiar to many of you:
This approach works as long as your XML documents do not change too much.
What happens when the structure of the generated document has to change depending on certain input and multiple namespaces are involved? How do you collect used namespaces? How do you add new fragments programatically?
It starts getting complex, and using templates is not a solution anymore.
Using DOM is certainly an option:
It’s definitely an improvement over the first approach, but there are still some drawbacks:
- Nested elements requires creating subelements and nesting them one by one
- Adding elements with different namespaces requires working with namespaces and tag names separately
- You have to be extra careful with namespace prefixes.
\DOMDocument
creates its own (ugly) prefixes by default, but it also accepts prefixing the tag name with your own custom prefix (danger zone!)
I came across multiple problems when generating XML documents for AgenDAV. Under the hood, a lot of XML has to be generated (and parsed, but that’s another story), and dealing with multiple namespaces was starting to be difficult. Nesting elements required lots of code and started to get confusing too.
Fortunately I found a solution to all my XML writing issues: the sabre/xml package. Its author is a much respected PHP developer, Evert Pot, who produces really high quality packages that I use on some of my projects.
Using sabre/xml to write XML documents
sabre/xml XML generation is based on
XMLWriter, which is part of PHP core since 5.1.2.
This package extends the native XMLWriter
class so it does a better job.
Before starting with sabre/xml, let me introduce Clark notation to you. In my opinion, sabre/xml is awesome thanks to supporting it.
Clark notation is a way of writing an XML element including both the namespace and the tag name in just one string. The namespace goes before the tag name wrapped in braces. So the following string in Clark notation:
{http://myns.org/}/tag
Can be understood as:
That means you have not worry anymore about namespace prefixes and their definitions. sabre/xml will let you specify fully namespaced elements while doing the difficult parts by itself. Isn’t that great?
Installing sabre/xml is really simple using composer:
Let’s rewrite our example:
Pretty self explaining, I hope. Writing XML like this lets you do it sequentially, opening and closing XML elements as you go. It even handles namespaces and prefixes.
You can see we have used two different syntaxes:
startElement($element)
andendElement()
write()
There some other ways of doing it using sabre/xml, but I found these two to be more than enough for most cases.
As it handles Clark notation, we can now do call the generatePayload()
like this:
Let’s see the output:
While it is valid XML, we can improve it by providing Sabre\Xml\Writer
with some frequently used
namespaces in our document and a custom prefix. We could just add the following after the
openMemory()
call:
The XML document generated would be much nicer:
We can even decouple the generation of the <permissions>
block from the original function:
After discovering sabre/xml, my relationship with XML has changed, and my code is now cleaner.
sabre/xml describes itself as An XML library for PHP you may not hate, and I agree. Not only do I hate it, but I certainly love it!