Posts Tagged ‘SimpleXML’

PHP and XML manipulation

Thursday, May 28th, 2009

Recently I’ve been fiddeling around with an old project of mine, and decided to extend it into a full-blown framework, just for kicks. Born from GDO, a ORM layer for PHP, it’s supposed to serve no real purpose but personal gratification.

Anyway, parallel with the framework I am building a website to showcase it. I also decided that in this specific case all the HTML documents should be built from either PHPs DOM or SimpleXML libraries, I personally dislike having HTML strewn across the project, so I’ve seperated structures like forms and tables into classes and the idea is that I can simply append them to the current page at a specific node and it’ll render the HTML when everything is added.

The problem

Here in lies the problem, PHPs XML libraries (at least the ones that I tried) require you to drag the top node to which you want to append whatever around in all helper classes and such, allow me to demonstrate.

<?php
$document = new DOMDocument();
 
$table = new DOMElement('table');
 
$row = new DOMElement('tr');
$row->appendChild(new DOMElement('td', 'test element'));
 
$table->appendChild($row);
$document->appendChild($table);

One would expect this all to work out fine and produce the following XML document;

<?xml version='1.0' encoding='utf-8' ?>
<table><tr><td>test element</td></tr></table>

In fact, it won’t. It won’t even run. PHP bails out during run time with the error “DOMException: No Modification Allowed Error“. This is because every DOMElement object not created with DOMDocument::createElement() is by default read-only, as you can read in the description of DOMDocument::__construct().

Besides begging the PHP developers to make every DOMElement not read-only on construction, the obvious solution would be to add the DOMElement in question to the DOMDocument and continue building from there, but that’s the problem. It seems counter-intuitive to pass the DOMElement or DOMDocument that you want to append your seperate structure to to every constructor of every XML producing class (or via normal methods of course).

I’ve taken the literal example of PHPs DOM classes, but I’ve tested SimpleXML as well, which provides even less flexibilty regarding node reuse and other fancy stuff one could want to do with XML documents.

Workarounds

There are several solutions to this problem, to name a few:

  • Create a singleton class that holds one instance of DOMDocument, and use a wrapper method somewhere to either get a valid DOMElement
  • Have all classes that produce XML nodes use a fake DOMDocument, and then use DOMDocument::importNode() at the return-point to import the nodes (very inefficient, especially when using a deep-copy).
  • Have the classes that produce XML nodes return nested arrays containing all name -> content relations of the nodes and run through them when it’s sensible to do so.

I’ll leave it as an exercise to the reader to pick out the best method. I haven’t found a solution yet, but I hope to contact the DOM XML module maintainer and discuss this with him/her.