PDA

View Full Version : Filtering XML results in PHP



camargo
August 27th, 2007, 01:50 PM
Hello Kirupans,

I have another post here regarding a PHP/XML issue I ran into, but I'm going to start a new topic here since I feel this is a question that deserves one. Why? Well because it's quite a mouthful.

I'm in the process of creating a page that displays multiple lines of inventory for a bunch of products (let's call them 'widgets'). The widgets are listed in XML format (they'll end up being pulled from a MySQL DB eventually).

<inventory>
<widget>
<name>One</name>
<color>Red</color>
<weight>5</weight>
<price>15</price>
</widget>
<widget>
<name>Two</name>
<color>Blue</color>
<weight>8</weight>
<price>21</price>
</widget>
<widget>
<name>Three</name>
<color>Green</color>
<weight>3</weight>
<price>12</price>
</widget>
<widget>
<name>Four</name>
<color>Red</color>
<weight>15</weight>
<price>35</price>
</widget>
</inventory>
Now, I have a PHP page that opens up my XML file using SimpleXML:

<?php
$xml = simplexml_load_file('inventory.xml');
?>Then it will display information for each widget in a nice, neat format:

<?php
foreach ($xml->widget as $widget) {
echo "<div class='widget'>";
echo "<span class='name'>" . $widget->name . "</span>";
echo "<span class='color'>" . $widget->color . "</span>";
echo "<span class='weight'>" . $widget->weight . "</span>";
echo "<span class='price'>" . $widget->price . "</span>";
echo "</div>";
}
?>My question to you is, how would I go about building a function that would filter the results to this page. For instance if there was a set of check-boxes that allowed you to only display the "Red" or "Blue" colored widgets. Or perhaps I only want to see "Red" widgets that have a price less than "20".

Any help or pointers are completely appreciated. Thanks in advance Kirupans!

camargo
August 27th, 2007, 06:38 PM
Okay, so it looks like this is turning out to be a joint effort. I asked this same question over at the PHPFreaks.com forums. Unfortunately, the response given to me seems to be above my head when it comes to reading it logically. I'm simply confused on how to execute it, or why its doing what it's doing...

Here's what I was told to use:

<?php
$str = '<inventory>
<widget>
<name>One</name>
<color>Red</color>
<weight>5</weight>
<price>15</price>
</widget>
<widget>
<name>Two</name>
<color>Blue</color>
<weight>8</weight>
<price>21</price>
</widget>
<widget>
<name>Three</name>
<color>Green</color>
<weight>3</weight>
<price>12</price>
</widget>
<widget>
<name>Four</name>
<color>Red</color>
<weight>15</weight>
<price>35</price>
</widget>
</inventory>';

function xmlfilter ($x, $color, $weight, $maxprice)
{
$xml = simplexml_load_string($x);
$res = array();
foreach ($xml->widget as $w)
{
$keep = 1;
if ($color!='')
{
if ((string)$w->color != $color) $keep = 0;
}
if ($weight!='')
{
if ((string)$w->weight != $weight) $keep = 0;
}
if ($price!='')
{
if ((int)$w->price > $maxprice) $keep = 0;
}
if ($keep) $res[] = $w;
}
return $res;
}
$filtered = xmlfilter($str,'Red','',20);
echo '<pre>', print_r($filtered, true), '</pre>';
?>

camargo
August 27th, 2007, 09:03 PM
Whew! Okay Kirupans, I am doing this because I not only want to get some input from you guys, but I'd also love to share progress with you. Who knows, one of you may want to do this in the future.

Here's what we've created so far. And I'll notate as best as possible.

Let's take a look at the form we would be creating here.

<form>
Select color <input type="radio" name="color" value="Red"> Red
<input type="radio" name="color" value="Green"> Green
<input type="radio" name="color" value="Blue"> Blue
<br/>
Max weight <input type="text" name="weight" size="5"><br/>
Max Price <input type="text" name="price" size="5"><br/>
<input type="submit" name="sub" value="Submit">
</form>This form allows us to choose a color, maximum weight, and maximum price for our filter. We need to build the PHP script that responds to this form's values.

Let's take a look at the full PHP code that makes this work (comments inside code below):


<?php

//load up the XML file as the variable $xml (which is now an array)
$xml = simplexml_load_file('inventory.xml');

//create the function xmlfilter, and tell it which arguments it will be handling
function xmlfilter ($xml, $color, $weight, $maxprice)
{
$res = array();
foreach ($xml->widget as $w)
{
//initially keep all elements in the array by setting keep to 1
$keep = 1;
//now start checking to see if these variables have been set
if ($color!='')
{
//if color has been set, and the element's color does not match, don't keep this element
if ((string)$w->color != $color) $keep = 0;
}
//if the max weight has been set, ensure the elements weight is less, or don't keep this element
if ($weight)
{
if ((int)$w->weight > $weight) $keep = 0;
}
//same goes for max price
if ($maxprice)
{
if ((int)$w->price > $maxprice) $keep = 0;
}
if ($keep) $res[] = $w;
}
return $res;
}

//check to see if the form was submitted (the url will have '?sub=Submit' at the end)
if (isset($_GET['sub']))
{
//$color will equal whatever value was chosen in the form (url will show '?color=Blue')
$color = isset($_GET['color'])? $_GET['color'] : '';
//same goes for these fellas
$weight = $_GET['weight'];
$price = $_GET['price'];

//now pass all the variables through the filter and create a new array called $filtered
$filtered = xmlfilter($xml ,$color, $weight, $price);
//finally, echo out each element from $filtered, along with its properties in neat little spans
foreach ($filtered as $widget) {
echo "<div class='widget'>";
echo "<span class='name'>" . $widget->name . "</span>";
echo "<span class='color'>" . $widget->color . "</span>";
echo "<span class='weight'>" . $widget->weight . "</span>";
echo "<span class='price'>" . $widget->price . "</span>";
echo "</div>";
}
}

?>
Note that only the elements of the array $xml that passed the filter were allowed to go through to the new array, $filtered.

By default, every element will pass the filter. That's why we started with $keep = 1. Then, though a series of if statements, we pushed one-by-one through each property and set $keep = 0 for any that we didn't want in the final output.

I said "whew," right? Well I meant it. Okay, so the final stage of this whole thing is probably going to need your assistance.

"Why?" you ask. Well because I'd like this whole process to happen without the page refreshing. That's right, through good ol' AJAX. So if any of you can give me pointers on that front, please do so!