By Harry Fuecks

Thoughts on using DOM as a template engine

By Harry Fuecks


  • seratonin

    I hope that the powerful XML features in PHP 5 will motivate developers towards a standards-based solution for templating (e.g. DOM, XML/XSLT, etc.). Personally, I use the DOMDocument class to build an XML document and then transform it into XHTML using XSLT.

  • That is what Amrita is doing in the Rubyworld for ages. I wonder if you talk about this concept?

  • mwmitchell

    Amrita? Have a look at this:


  • hlellelid

    This is brilliant. I’ve long been wanting to write an XMLC port for PHP. I started a couple years ago, but in PHP4 the DOM stuff just wasn’t capable of handling the HTML, but (as mentioned) now w/ HTML support in DOM via libxml2 this is possible — and very exciting.

  • mindlace

    See also: Zope Page Templates, nevow.

    Though really, if we just all stick to xslt and dom transformations, we’ll win a whole lot more interoperability in the long run

  • I’m in favour of using the DOM and/or XSL-T but the more options available, the better.

    Not sure about XMLC but if it’s that cool, then why not for PHP huh ?

  • Jason Earl

    How about the idea of combining both DOM and SAX together ?

    A little while a ago I experimented with a template system like Xaraya’s, but used Harry’s HTML SAX Parser instead. The template system it’s self was a bit crappy, and I was not happy with the idea of implementing logic statements like Xaraya. I also found it to be cumbersome as there were places where there was a need to use template command tags inside thngs like HTML attirbutes. In order to do this, you need to have a hacked parser (for instance I hacked Harry’s parser by extending the class dealing with the tokenisation / events) to get round this as the markup is not valid XML.

    Looking at ASP.NET and WACT, they use a runat=”server” attribute, which gets round this.

    Looking at WACT, there is a lot of dupilcation between it and DOM. It in essance is using HTML_SAX to get round badly formed markup (i.e. Oldskool HTML). On top of that, it uses classes for each tmplate command, much like Xaray does, which is the obvious thing to do. However because there is no control (or way of using a callback) in DomDocument::loadXML(), you can not deligate the DOM tree nodes as specialised classes like in WACT.

    As I am working on a Portal system, I have decided to work on something that is much based on ASP.NET / WACT templates (Yeah I know, I’m reventing the wheel here, but I’m looking at from more of a ‘learning curve’ perspective). Seeing as I am using PHP5, I will be using something like the built in SAX, or HTML_SAX (I trust HTML_SAX more than I trust PHP’s SAX parser). The big change from WACT will be that template command classes will be inherited from the DOM API. This means I don’t have to Tree handling methods myself. Extending DOM classes allows one to stick to a standards complient interface, validation through things like DTD’s and the added power of XPath.

    The other small pointless advantage of this is that this parsing system can be used in situations where the data is not in an XML format, but needs to be parsed into a tree. All you need to do is replace the SAX parser. (For instance dealing with config files)

    — Just my 2 cents

  • Fascinating post. In general think what you describe will work well in particular this part;

    Extending DOM classes allows one to stick to a standards complient interface, validation through things like DTD’s and the added power of XPath.

    One problem we’ve got in WACT is how to have tags which generate HTML generate XHTML if it’s needed. It can be done on a per-case basis (with effort in each case) but a generic solution that involves less effort would be great. Having template elements represented with DOM opens the way to tools that could make it easier.

    One question – are you planning a runtime / compile time division (which Jason drew nicely here)?

    With DOM I guess you could insert processing instructions into the tree, which hold PHP code, then store the finished tree in a file, which should be more or less ready to execute as a PHP script. Problem there is how then do you manipulate the template at runtime, without reinvoking DOM (and the overhead that may carry)?

  • Jason Earl

    One question – are you planning a runtime / compile time division

    Well, the idea of mixing DOM and SAX was an idea I came up with a few minutes before seeing this blog entry (as I was surfing the net looking into the different XML options in a bit more detail for PHP5 before I dived into coding).

    As a result, I have not thought into much detail how I will code this yet :-S. I am very insprised by the way WACT does things. Originally I planned to use WACT for IDK, my CMS/Portal system. (which really is turning more of a framework project atm)(BTW, if you look at the RFC Docs on that site, please ignore the template system stuff as I have scraped the idea of the Xaraya-like template system in favour of an ASP.NET/WACT one). In the beginning, I was going to clean up the code for the mock up Xaraya-like template system I wrote many months back. Then I came across WACT’s template system, and at the same time, my boss mentioned the idea of ASP.NET style templates when I raised the idea of writing a common framework to save reinventing the wheel for each project we do. Originally, I was going to just going to use the WACT template system as it was, as it does do what we need (like wise I was going to use it in my CMS/Portal project).

    Anyway, my boss said he wanted to write in-house something from scratch. This is partly due to the fact because he hates relying on other peoples source code, but mainly because he wanted it to be done as a learning curve/point of view. This is why I am reinventing the wheel here by making yet another template system. This enables my boss to learn about OOP programming/UML/design patterns from me, as he will see the development of the code. On top of this, because I’m writing it for PHP, I wanted to make use of as much use of the new PHP5 features such as Exceptions, built in DOM API (and maybe the internal SAX API seeing as the focus at work is to make everything 100% XHTML 1.0 Strict, so it won’t matter if SAX barfs at any typos/bad markup).

    Anyway, as I was saying, I want to work on something that works like WACT where there is a DOM tree at the parsing stage, and likewise there is a basic DOM system in place at run time to manage the runat=”server” clauses in the template. The way this probably will work is I will make a class that inherits the DomElement class for each server side tag. Each server tag will have a unique ID, (even if no id tag was defined in the template), this will for tags to be addressed using existing DOM methods like DOMDocument::getElementById()

    As for what the compiled outcome will look like …

    < ?php /* Basic DOM root created here */ $root = new DomDocument(); /* basic ***single*** container for server tags */ $curElement = &$root->createElement('root_container');
    /* Bind to doc root */
    /* Setup a tag stack */
    $parseStack[] = &$curElement;
    HTML garbage here :)

    < ?php /* * Create a new server tag here. * This could use the prototype pattern here to clone an 'base' object * maybe (cloning is faster in PHP5 than new?) */ $tagId001 = &Repeater::CreateInstance(array( 'attribute1' => 'attrib data'
    echo $tagId001->Open();
    * Here I would put code to Bind this tag to
    * the parse tree / parse stack

    < ?php $tagId001->Close();
    /* Here I would put code to remove from the parse stack array */
    Trailing HTML Garbage continues :D

    This Repeated data :)

    As you can see this doesn’t hold the compiled PHP code in a DOM tree. I never intended to go down this route as the code would need a lot of overhead as the DOM system would need be called at run time to generate the PHP code, which then needs to be parsed via eval. This is a major point of weakness as it means bytecode caching systems like Zend Optimiser and Turck MMCache can not hold code in their internal hash tables as the end code is not getting run from the file system. Instead, as you can see I am only using DOM in the runtime to hold the structure of server side tags, and not any other data (and thus I am not using any of the {Load|Save}XML methods here. This gives me the advantage of being able to use things like XPath (very good if I have a

    set to run at server, and I wanted to use it to extract all the ,

    Basically, by taking this runtime approach (which I think is similar to WACTs, though I have not studied WACT in any depth to confirm this), I can use the native DOM system to work with server side tags with not too much overhead.

    As far as compile time goes, I will make it so that every element gets put in a DOM tree before the output is made. I was thinking of making my DOM extended node classes to implement the string casting operator (__toString method). This means I can just do $compiled = (string)$CompileTree; to compile my code (I just think this looks cool :P). By having everything in a DOM at compile time it allows for badly marked up templates to be corrected.

    So in a short answer, yes, I do plan on a Runtime/Compile division. The template system is very much going to be like WACT, but reworked under the bonnet so that it’s more intune with PHP5.

    When I complete the compiler I will look into working on some nice Command Classes for the engine. As my boss said it would be so nice to do repeaters, lists etc using a template engline like this/WACT/ASP.NET as it will allow me and my boss to employ some “trained monkeys” where we work to do all the boring work for us. Currently the DreamWeaver Server Behaviours are nasty and massy to work with (and prone to errors). replacing them with this will allow trained monkeys to make our front ends.

    Going back to making nice Command tags, I will extend the basics that WACT and ASP.NET offers. For instance, if I write a small poll / survey system, I could do something like

    Yes No I perfer nasty Java, but thankies for asking

    on my template if I wanted a poll. This Poll command could even do the job of inserting extra styles for the elements needed in div.nicelookingpoll in to a tag at the top of my page.

    Again, this extends the idea of making a site that is totally dummy proof, thus making it posible for trained monkeys to create sites. All sorts of Command tags can be made for any items that are commonly used in web pages. In a CMS, it would be lovely to be able to have something where you have something like…





    Now, imagine this… all of the tags with edit_region attributes could be made so if a user with admin access is logged in, it would show a small “Edit” link by the tags. Upon clicking this would make the page reload, but instead it would switch the HTML element into a tag or in the case of a type=”rich_text”, would load up a textarea which uses Javascript to load up a Rich text WYSIWYG editor like FCKeditor/HTMLArea. Wouldn’t this be amazing ? Now add in the extra concept of making your framework use Access Control List Based Permissions (for max scalablity and easy administration), and then imagine if this lovely little system also did stuff like like add in the CSS Class info in a CSS file for you (you could get it so that propertyName element is bould to use a css class called PropertyName, and then make it so when you click edit on ProprtyName, you also get a Mini CSS editor).

    The list of things you can do with this command tags would be endless!!! (These sort of features could be added to WACT’s template system, as these sort of features are not dependant on the DOM backend).

    Anyway that was probably a little more than 2 cents. Lets hope I still have enough cash to buy lunch at work on Monday.

  • drydenmaker

    wow! that was long. Sounds like a lot of over complication to me, maybe I am missing something. How long to you plan on training your monkeys in your scripting language you outlined. Wouldn

  • tqvpllxzhb

    Hello! Good Site! Thanks you! ukzcqcahrlfg

Get the latest in Front-end, once a week, for free.