PHP offers two methods of parsing an XML document. You've already seen how SAX works; in this article, find out how to use PHP's DOM functions to traverse an XML tree, and also learn about important differences between the two approaches.
I can do the same thing with the second example as well. However, since there are quite a few levels to the document tree, I've decided to use a recursive function to iterate through the tree, rather than a series of "if" statements.
Here's the XML file,
<?xml version="1.0"?>
<recipe>
<name>Chicken Tikka</name>
<author>Anonymous</author>
<date>1
June 1999</date>
<ingredients>
<item>
<desc>Boneless chicken
breasts</desc>
<quantity>2</quantity>
</item>
<item>
<desc>Chopped
onions</desc>
<quantity>2</quantity>
</item>
<item>
<desc>Ginger</desc>
<quantity>1
tsp</quantity>
</item>
<item>
<desc>Garlic</desc>
<quantity>1
tsp</quantity>
</item>
<item>
<desc>Red chili powder</desc>
<quantity>1
tsp</quantity>
</item>
<item>
<desc>Coriander seeds</desc>
<quantity>1
tsp</quantity>
</item>
<item>
<desc>Lime
juice</desc>
<quantity>2
tbsp</quantity>
</item>
<item>
<desc>Butter</desc>
<quantity>1
tbsp</quantity>
</item>
</ingredients>
<servings>
3
</servings>
<process>
<step>Cut
chicken into cubes, wash and apply lime juice and salt</step>
<step>Add
ginger, garlic, chili, coriander and lime juice in a separate
bowl</step>
<step>Mix
well, and add chicken to marinate for 3-4 hours</step>
<step>Place
chicken
pieces on skewers and barbeque</step>
<step>Remove, apply butter,
and
barbeque again until meat is tender</step>
<step>Garnish with lemon
and
chopped onions</step>
</process>
</recipe>
and here's the script which parses it.
<html>
<head>
</head>
<body bgcolor="white">
<hr>
<?
// data
file
$file = "recipe.xml";
// hash for HTML markup
$startTags = array(
"name"
=> "<font size=+2>",
"date" => "<i>(",
"author" => "<b>",
"servings"
=> "<i>Serves ",
"ingredients" => "<h3>Ingredients:</h3><ul>",
"desc"
=> "<li>",
"quantity" => "(",
"process" => "<h3>Preparation:</h3><ol>",
"step"
=> "<li>"
);
$endTags = array(
"name" => "</font><br>",
"date" => ")</i>",
"author"
=> "</b>",
"servings" => "</i>",
"ingredients" => "</ul>",
"quantity"
=> ")",
"process" => "</ol>",
);
// create a document object
$dom = xmldocfile($file);
//
get reference to root node
$root = $dom->root();
// get children
$children =
$root->children();
// run a recursive function starting here
printData($children);
//
this function accepts an array of nodes as argument,
// iterates through it and
prints HTML markup for each tag it finds.
// for each node in the array, it then
gets an array of the node's
children, and
// calls itself again with the array
as argument (recursion)
function printData($nodeCollection)
{
global $startTags,
$endTags;
// iterate through array
for ($x=0; $x<sizeof($nodeCollection);
$x++)
{
// print HTML opening tags and node content
echo $startTags[$nodeCollection[$x]->name]
. $nodeCollection[$x]->content;
// get children and repeat
$dummy = getChildren($nodeCollection[$x]);
printData($dummy);
//
once done, print closing tags
echo $endTags[$nodeCollection[$x]->name];
}
}
//
function to return an array of children, given a parent node
function getChildren($node)
{
$temp
= $node->children();
$collection = array();
$count=0;
// iterate through children
array
for ($x=0; $x<sizeof($temp); $x++)
{
// filter out the empty nodex
//
and create a new array
if ($temp[$x]->type == XML_ELEMENT_NODE)
{
$collection[$count]
= $temp[$x];
$count++;
}
}
// return array containing
child nodes
return
$collection;
}
?>
</body>
</html>
In this case, I've utilized a slightly different method to mark up the XML. I've
first initialized a couple of associative arrays to map XML tags to corresponding HTML markup, in much the same manner as I did last time. Next, I've used DOM functions to obtain a reference to the first set of child nodes in the DOM tree.
This initial array of child nodes is used to "seed" my printData() function, a recursive function which takes an array of child nodes, matches their tag names to values in the associative arrays, and outputs them to the browser. It also obtains a reference to the next set of child nodes, via the getChildren() function, and calls itself with the new node collection as argument.
By using this recursive function, I've managed to substantially reduce the number of "if" conditional statements in my script; the code is now easier to read, and also structured more logically.