An Alternative PHP/XPath Implementation: PHP.XPath
In the words of its developers, PHP.XPath is ". . . a PHP class for searching an XML document using XPath, and making modifications using a DOM style API . . . [it] does not require the DOM XML PHP library". The class, which is maintained as an open source project on the SourceForge network (http://www.sourceforge.net) by Nigel Swinson, Sam Blum, and Daniel Allen, is released under the Mozilla Public License, and is freely downloadable from http://www.sourceforge.net/projects/phpxpath.
 SourceForge.net. "Project: PHP.XPath Summary." Available from the Internet: http://www.sourceforge.net/projects/phpxpath.
As the previous description suggests, there isn't anything very complicated about the PHP.XPath class. It accepts XML data (either a file or a string) as argument, parses the data, and creates an object representing the XML document. The methods exposed by this object allow developers to create XML nodesets based on XPath expressions; add, edit, and delete nodes from the document tree; and extract character data embedded within specific XML elements. In order to demonstrate how the class works, let's consider a simple example (see Listing 8.5).
Listing 8.5 A simple XML Document (market.xml)
Today in the market, I spy
<vegetable color='purple'>aubergines</vegetable>, and
Listing 8.6 demonstrates using the PHP.XPath class to obtain a collection of all the <fruit> elements within the document (via an XPath expression), and print the contents of each of these elements in an HTML list.
The Number Game
All the examples in this section use version 2.1 of the PHP.XPath class.
Listing 8.6 Extracting a Node Collection from an XML Document with PHP.XPath
The following fruits were encountered in this document:
// include class
the first step is to instantiate an object of the class
the constructor accepts the name of an XML file as argument;
it then parses this XML file and creates a context for subsequent XPath queries
$xpath = new XPath("market.xml");
next, retrieve a collection of <fruit> nodes
the match() method accepts an XPath expression as argument,
and returns a node collection matching that expression, as an array
$nodeCollection = $xpath->match("//fruit");
// want to see what it looks like?
// uncomment the following line
finally, iterate through the returned node collection
and print the content of each node
the getData() method returns the content (character data)
of a particular node
foreach($nodeCollection as $node)
echo "<li>" . $xpath->getData($node);
The PHP.XPath class exposes a number of different methods; however, the two you're likely to use most often are the match() and getData() methods. The match() method evaluates a specific XPath expression within the context of the selected XML document and returns an array of nodes matching the expression; whereas the getData() method extracts the content, or character data, of a specified node.
With this fundamental understanding in place, it's possible to use the PHP.XPath class for even more complex operations. In order to illustrate this, I will rewrite the data tabulation program first seen in Listing 3.12, using the PHP.XPath class instead of PHP's native DOM and XPath functions. Listing 8.7 contains the XML source, which needs to be collated, averaged, and presented in a 2x2 table.
Listing 8.7 A Compilation of Experiment Readings (data.xml)
<!-- data for 3 cultures: Alpha, Beta and Gamma, tested at temperatures ranging from
10C to 50C -->
<!-- readings indicate cell counts 4 hours after start of experiment -->
<!-- snip -->
Listing 8.8 has the code that actually does all the work.
Listing 8.8 Averaging and Tabulating Experiment Readings with PHP.XPath
// include class definition
// XML file
$xml_file = "data.xml";
// create arrays to hold culture/temperature list
$cultures = array();
$temperatures = array();
// create XPath object
$xpath = new XPath($xml_file);
// get a list of "culture" nodes
$nodeset = $xpath->match("//culture");
// ...and create an array containing
// the names of all available cultures
for ($x=0; $x<sizeof($nodeset); $x++)
$cultures = $xpath->getData($nodeset[$x]);
// strip out duplicates
$cultures = array_unique($cultures);
// do the same thing for temperature points
$nodeset = $xpath->match("//temperature");
for ($x=0; $x<sizeof($nodeset); $x++)
$temperatures = $xpath->getData($nodeset[$x]);
$temperatures = array_unique($temperatures);
// sort both arrays
<table border="1" cellspacing="5" cellpadding="5">
// first row of table, print culture names
foreach($cultures as $c)
foreach($temperatures as $t)
// create as many rows as there are temperature points
// for each intersection (culture, temperature)
// print average of available readings
foreach($cultures as $c)
echo "<td>" . intersection($t, $c) . "</td>";
// this function collects all readings for
// a particular culture/temperature
// totals them and averages them
function intersection($temperature, $culture)
// get a reference to the XPath object
// set up variables to hold total and frequency
$total = 0;
$count = 0;
// get a list of "reading" nodes
// for records with culture c and temperature t
$nodeset = $xpath->match("//record[culture='" . $culture . "' and temperature='" .
$temperature . "']/reading");
// iterate through nodeset
// add the readings
foreach ($nodeset as $reading)
$total += $xpath->getData($reading);
// and then average them
if ($count > 0)
Listing 8.8 uses three different XPath expressions. The first two are used to create a list of available cultures and temperature points (they are required for the row and column headings of the table), whereas the third XPath returns a list of nodes matching a specific culture and temperature. With all this in place, all that's left is to add the readings associated with each of these nodes to reach a total number, and divide that total number by the number of nodes (readings) to obtain an average cell count.
Again, most of the work here is done by the match() and getData() methods, which make it possible to easily create subsets of XML elements matching a specific criteria, and retrieve the data contained within them.
This is just one example of many. The PHP.XPath class comes with a remarkably full-featured API, which opens up numerous possibilities to the creative developer. Examples and documentation are available at the official web site for the project (http://www.sourceforge.net/projects/phpxpath), together with introductory material to get you started.
Plug In, Click Through
Drop by this book's companion web site for links to other open source XML/PHP alternatives.