Last Updated:

PHP: Using XML Paser Functions when working with templates

Although the idea of separating code and data is not new, it remains relevant. Convenience is undeniable - since people modifying data often do not have to have access to the code.

In PHP, the syntax of the language is based on not embedding code in data and in this article we will look at one of the most convenient ways to separate them. The method will be based on XML.

Consider the following task: We have many clients, and almost every one of them wants to see a guestbook on their website. Each time we are tired of changing the source code of the guestbook. And there is no question that the error that we found, installing the guestbook for the eighteenth time, had to be corrected by hand on the previous seventeen sites.

Data:

In order to avoid such a problem, it is necessary to separate the data from the code. We would like the appearance of the guestbook to be stored in a separate file, the dynamic data (records) stored in the database, and the code in a separate directory.

So, we could quickly correct the mistake by simply replacing the old code with a new one, while preserving the original design.

Let's describe a guestbook template using XML as follows:

 
Code:
 
<?xml version="1.0" encoding="windows-1251"?>

<guestbook>
<include url=".. /top.html" />

<![ CDATA[
<H3>Guest book - place for trep</H3>
<table width=100% cellspacing=5><tr><td>
<br><center>
]]>

<record><![ CDATA[
<table cellpadding=7 cellspacing=0 bgcolor=#F0F8F8 width=95%>
<tr bgcolor=#E0F0F0><td>__NAME__
(<a href=mailto:__EMAIL__>__EMAIL__</a>)</tr>
<tr><td>__COMMENT__
</td></tr>
</table>
<br>
]]></record>

<![ CDATA[
<br>
<center><BR><font face=Verdana size=2>
<A href=/add/> Add record </A>
</font></center>
</td></tr></table>
]]>

<include url=".. /bottom.htm />

</guestbook>
 

Each template consists of a main section <guestbook></guestbook> within which a section of <records></record> describing a single entry in the guestbook, can be placed.

In addition, there may be a single tag <include />, the location of which will be inserted in the document described using the url property, for example:

 
Code:
 
<include url=".. /bottom.htm />

The following is an abbreviation of the diagram of the document described:

 
Code:
 
<?xml version="1.0" encoding="windows-1251"?>

<guestbook>
<include url=".. /top.html" />
<record>
the body of one entry
</record>
<include url=".. /bottom.htm />
</guestbook>

Code:

Just a little bit left - to write a program that will turn the template described above into an HTML document containing both the appearance and dynamically changing data (notes in the guestbook)

To process the template, we will use XML Parser functions (http://www.php.net/manual/en/ref.xml.php). This PHP extension provides access to the functionality of the Expat library, authored by James Clark. The Expat library is written in C and is designed to parse XML documents based on events. it does not check the xml document for errors and does not work with the xml document model object because some other libraries (such as tinyXml) do)

In PHP 4.3.1 (and possibly earlier versions), XML Parser functions are supported by default.

Let's proceed directly to writing the program - the template handler.

First, we consider the template into a variable $xmldata:

 
 
Code:
 
<?
$xmldata=implode("",file("template.xml"));
Associative array - stores data corresponding to tags.
$TMPL=Array();
The $ce=""" tag
to be processed;
/*

...

missed connection to MySql

server ...

*/

$result=mysql_query("SELECT * FROM guestbook_database"
);

In the variable $html, we will output the result of our script. At the very end, we'll just print $html;

 
 
Code:
 
$html="";

Creating an XML Document Handler Object

 
 
Code:
 
$xml_parser = xml_parser_create();

We set options and handlers for it. The startElement() function will be called when an opening tag is encountered in the XML document. The endElement() function will be called when the closing tag is encountered. For data (what is inside the tag), the characterData() function will be called xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true); xml_set_element_handler($xml_parser, "startElement", "endElement"); xml_set_character_data_handler($xml_parser, "characterData");

Call the XML document handler

 
Code:
 
if (! xml_parse($xml_parser, $xmldata)) {
$error=sprintf("Pattern error: %s at line %d",
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser));
die();
}

xml_parser_free($xml_parser
);
 

Data output

 
 
Code:
 
print $html;

Now let's look at the main part - these are three handler functions:

  • startElement()
  • endElement()
  • characterData()

In the global variable $ce remember the name of the tag being processed so that the characterData() handler knows which element of the array $TMPL append the content to.

 

Code:
 
function startElement($parser, $name, $attrs) {
GLOBAL $ce,$TMPL,$html;

switch ($name) {
case "INCLUDE":
$html.=@implode("",@file($attrs["URL"]));
break;
}
$TMPL[$name]="";
$ce=$name;
}


function endElement($parser, $name) {
GLOBAL $ce,$TMPL,$result,$html;

switch ($name) {
case "RECORD":
while ($D=mysql_fetch_array($result)) {
$t=$TMPL[ "RECORD"];
$t=str_replace("__NAME__",$D["name"],$t);
$t=str_replace("__EMAIL__",$D["email"],$t);
$t=str_replace("__COMMENT__",$D["comment"],$t);
$html.=$t;
}
break;
}
$ce="";
}


function characterData($parser, $data) {
GLOBAL $ce,$TMPL,$html;

switch ($ce) {
case "RECORD":
$TMPL[$ce].=$data;
break;
default:
$html.=$data
;
        }
    }
 

That's kind of it. If you have dealt with "XML parser functions", I recommend that you study "XSLT functions" and "DOM XML functions". They will help you solve such problems.