patTemplate and patXMLRenderer
patTemplate is a rendering engine that attempts to simplify web application development by using a template-based framework to separate presentation information from data. It does this by using simple templates to hold presentation semanticsformatting, layout, alignment, and so onand inserting placeholders in these templates to represent data elements. When these templates are rendered by the engine, the placeholders embedded within them are replaced by actual data, which may be dynamically retrieved from a database, a text file, or any other data source.
patXMLRenderer builds on the functionality offered by patTemplate, adding an XML parser to the mix. This allows data encoded in XML to be retrieved and used in a template, with the XML parser automatically creating appropriate variables and handing them off to the template engine for inclusion in the final output.
Together, patTemplate and patXMLRenderer provide a simple, efficient solution to the problem of generating HTML (or other ASCII) documents from XML-encoded data. Part of a larger suite of PHP-based application tools, they are developed and maintained by Stephan Schmidt, and can be downloaded free of charge from http://www.php-tools.de/.
The patXMLRenderer publishing system was designed around the following goals:
Separate content from its presentation
Allow for the easy transformation of raw data into any other format
Provide an extensible framework for the development of new application modules
It accomplishes these goals using a combination of PHP and XML programming techniques.
Assuming an XML data source, a patXMLRenderer publishing system consists of two primary components:
A template engine (patTemplate) that handles the creation and management of document templates and performs variable interpolation
An XML parser (patXMLRenderer) that parses one or more XML documents, retrieves data from them, and merges this raw data with the templates to produce a composite result.
As before, let's look at a couple of simple examples before diving into the code that drives the application. Consider Listing 9.11, which contains a simple template.
Each template is enclosed within a pair of <patTemplate:tmpl>...</patTemplate:tmpl> elements and has a unique name (in this case, "superhero"). As you'll see in Listing 9.12, this name attribute is used when assigning values to different template variables.
The uppercase strings you see enclosed within curly braces within the template definition (REALNAME, NICKNAME) are template variables; they serve as placeholders for actual data and will be replaced during the rendering phase.
Listing 9.12 demonstrates the PHP script that initializes the template engine, assigns values to the template variables, and puts the two together to create a composite result.
Listing 9.13 contains the resulting HTML document, with Figure 9.3 demonstrating what it looks like in a browser.
Figure 9.3. The HTML document generated by Listing 9.12, as it appears in a Web browser.
Let's see what happens when XML is added to the mix. Consider Listing 9.14, an XML shopping list.
Now, let's convert this XML-encoded list into a web page. The first step is to create a series of templates (compliant to the patTemplate format described earlier) to define the formatting and layout of this web page. Listing 9.15 contains the templates I'd like to use.
As you can see, the desired output is fairly simplean HTML document with the items in the shopping list displayed as elements of a bulleted list. In Listing 9.15, this simple HTML document is broken up into individual pieces, with each piece represented as a separate template.
The CONTENT marker that appears within each template is a special placeholder variable that is used by patXMLRenderer when it generates the final output. When a template is parsed by the rendering engine, the CONTENT placeholder is automatically replaced with the contents of the corresponding XML element (this may be either character data or other nested XML elements).
Those Amazing Acrobatic Attributes!
The CONTENT placeholder variable is not the only one recognized by patXMLRenderer. The class also allows you to import the values of XML attributes into the template, simply by using template variables corresponding to the attribute names.
Consider Listing 9.16, which has an XML document containing elements and element attributes.
When patXMLRenderer reads and combines this XML document with the template in Listing 9.17, the attribute values are automatically imported into the template as template variables and used to replace the template placeholders.
This capability to automatically convert XML attributes into template variables is unique to patXMLRenderer, and is one of the class' most useful features.
Finally, Listing 9.18 has the PHP script that initializes both the template engine and the XML parser, and generates the required output.
In this case, because the data will be coming directly from an XML file, there's no real need to manually define values for template variables with the addVar() method. Instead, when the patXMLRenderer engine is initialized, it parses the XML document, matches XML elements to templates (on the basis of the name attribute in the template definition), and replaces the placeholders in the template with data from the XML document. If you flip back to Listing 9.14, you'll see the correspondence between the XML elements used there and the name attributes used in Listing 9.15.
Listing 9.19 contains the resulting HTML code, and Figure 9.4 demonstrates what it looks like in a web browser.
Figure 9.4. The HTML document generated by Listing 9.18, as it appears in a web browser.
Though these are simple examples, they clearly demonstrate the potential of this system on a content-heavy web site. By separating the presentation of the data from the data itself, this system makes it possible to decouple the graphical interface of a web site from the data that appears within that interface, so web designers and content editors can (finally) work independently of each other.
As stated previously, the system consists of two components, which are implemented as PHP classes:
The patTemplate class, which handles the creation and management of document templates and performs variable interpolation
The patXMLRenderer class, which takes care of parsing XML documents, converting attribute values and character data into template variables, and displaying the rendered content
If you look at the source code for the patTemplate class, you'll see that it's fairly simple. It first reads and parses the available template(s), and then creates PHP arrays to hold the template name(s) and data. Listing 9.21 demonstrates a snippet from the readTempatesFromFile() method of this class.
In case you're wondering, the createParser() method of the class is used to actually parse the template file and obtain information on the templates within it.
After all the templates have been parsed, the next step is to obtain a list of template variables and values (remember that these variables must be manually defined by the application using the AddVar() method, as was done in Listing 9.12), and replace the variable placeholders in the template with their corresponding values. This is accomplished via the parseTemplate() method, which internally calls the parseStandardTemplate() method (see Listing 9.22).
Listing 9.22 A Function to Replace Variables in a Template with Their Actual Values (from patTemplate.php)
After variable interpolation has taken place (see the call to str_replace() in Listing 9.22), all that's left is to display the resulting output. This is taken care of by a little method called DisplayParsedTemplate(), which merely echoes the result to the output device.
So long as your activities are restricted only to patTemplate, the process described in the preceding paragraphs holds good. However, if you have a large amount of data, manually defining the values for a large number of template variables can get tedious. In such situations, it's easier to mark up your data in XML and let patXMLRenderer automatically import this data into your template(s).
A close look at the source code for the patXMLRenderer class reveals that most of the activity begins with the initRenderer() method, which sets the name of the XML file to parse, and also creates some global variables for use in the patTemplate class. Listing 9.23 has a snippet from this method.
Listing 9.23 A Function to Initialize the XML Parser and Set Some Global Template Variables (from patXMLRenderer.php)
Next, the getRenderedContent() method starts the process of parsing the XML file via the parseXMLFile() method. The parseXMLFile() method creates a parser via the createParser() method and processes it in chunks (see Listing 9.24).
Listing 9.24 The Functions to Create an XML Parser and Parse the XML Document (from patXMLRenderer.php)
As the parser steps through the document, callback functions are called to handle the different structures foundyou may remember this from Chapter 2, "PHP and the Simple API for XML (SAX)." These callbacksspecifically the end element handler endElement() take care of creating variable-value pairs from the character data in the XML document (see Listing 9.25 for a snippet from this function).
Listing 9.25 A Function to Assign Attribute Values and Character Data from the XML Document to Template Variables (from patXMLRenderer.php)
After all the template variables have been defined, the patTemplate class' getParsedTemplate() method is called to perform the variable interpolation, and the output is returned to the browser.
Isn't it simple when you know how?
patTemplate and patXMLRenderer demonstrate how the combination of an XML parser (which parses an XML document and retrieves data from it) with a PHP-based template engine (which separates content from presentation by means of placeholder variables) can substantially streamline the development process of a web application. This separation of presentation semantics from raw data not only increases efficiency by allowing a software development team to work independently of an interface design team, it also makes application code easier to maintain, update, and test. And no matter which way you look at it, this adds up to a Good Thing.