Jump to content

Filtering XML results in PHP


camargo

Recommended Posts

Hello fellow PHP Freaks,

 

I'm new here, and this is my very first post! So hello to you all! Here's my situation:

 

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 loads 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 with a price below "20".

 

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

Link to comment
Share on other sites

Something like

<?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 ((int)$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>';
?>

Link to comment
Share on other sites

Hi Barand,

 

Thanks for your quick response. As I look through the code you've written though, I seem to be clueless as to the execution of it. Perhaps I'm less advanced than I made myself out to be. I'm also having a hard time understanding the logic in the function. I'd hate to have you spell it out for me, but I think, in this case... I might need it. :-[

Link to comment
Share on other sites

Loop through the widgets.

 

for each widget, assume we keep it ($keep=1)

 

Now check if we are filtering by color (if $color != '' then we are)

If it's not the color we want then set keep to 0

 

Similarly with the other attributes.

 

If $keep is still 1 after the checks, add the widget to the results array

Link to comment
Share on other sites

Okay, I'm understanding the logic behind the function. Now how do I get the arguments from a form on the page? I see that the arguments here are already populated. I'm just not familiar with the process of taking a form's values and having PHP use them as arguments.

Link to comment
Share on other sites

<?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 ((int)$w->weight > $weight) $keep = 0;
        }
        if ($maxprice)
        {
            if ((int)$w->price > $maxprice) $keep = 0;
        }
        if ($keep) $res[] = $w;
    }
    return $res;
}

if (isset($_GET['sub']))
{
    $color = isset($_GET['color'])? $_GET['color'] : '';
    $weight = $_GET['weight'];
    $price = $_GET['price'];

    $filtered = xmlfilter($str,$color, $weight, $price);
    echo '<pre>', print_r($filtered, true), '</pre>';
}

?>
<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>

Link to comment
Share on other sites

I see! Barand you are extremely helpful! Now at the top of that script, you're defining $str as the full content of the XML file. What if I was to do:

 

$str = simplexml_load_file('inventory.xml');

 

Will this achieve the same effect?

Link to comment
Share on other sites

Alter slightly to read file

<?php

function xmlfilter ($xml, $color, $weight, $maxprice)
{
    $res = array();
    foreach ($xml->widget as $w)
    {
        $keep = 1;
        if ($color!='')
        {
            if ((string)$w->color != $color) $keep = 0;
        }
        if ($weight)
        {
            if ((int)$w->weight > $weight) $keep = 0;
        }
        if ($maxprice)
        {
            if ((int)$w->price > $maxprice) $keep = 0;
        }
        if ($keep) $res[] = $w;
    }
    return $res;
}

if (isset($_GET['sub']))
{
    $color = isset($_GET['color'])? $_GET['color'] : '';
    $weight = $_GET['weight'];
    $price = $_GET['price'];

    $xml = simplexml_load_file('inventory.xml');               // read xml file
    $filtered = xmlfilter($xml ,$color, $weight, $price);      // pass xml
    echo '<pre>', print_r($filtered, true), '</pre>';
}

?>
<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>

Link to comment
Share on other sites

Okay, so I'm 90% there. I've got all my variables setup and I can see how the form functions with the PHP. I've even been able to add filters of my own. But how do I get the data out of the filtered array without using print_r?

 

For instance, before I was able to do the following:

 

<?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>";
}
?> 

Link to comment
Share on other sites

replace the print_r bit with

    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>";
    }    

Link to comment
Share on other sites

Hey Barand! Let me show you what I was able to decypher. It ain't working yet, but perhaps you'll be able to tell me why.

 

I've gone ahead and written up a JS file:

 

var xmlHttp

function updateColor(str)
{ 
xmlHttp=GetXmlHttpObject()
if (xmlHttp==null)
{
alert ("Browser does not support HTTP Request")
return
} 
var url="ajaxFilter.php"
url=url+"?color="+str
xmlHttp.onreadystatechange=stateChanged 
xmlHttp.open("GET",url,true)
xmlHttp.send(null)
}

function stateChanged() 
{ 
if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
{ 
document.getElementById("results").innerHTML=xmlHttp.responseText 
} 
}

function GetXmlHttpObject()
{
var xmlHttp=null;

try
{
// Firefox, Opera 8.0+, Safari
xmlHttp=new XMLHttpRequest();
}
catch (e)
{
// Internet Explorer
try
  {
  xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
  }
catch (e)
  {
  xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
}
return xmlHttp;
}

 

Here's is the form that now calls the function when it changes (only focusing on color for now)...

 

<form>
Select color <select name="color" onchange="updateColor(this.value)">
                 <option value="red">Red</option>
                 <option value="blue">Blue</option>
                 <option value="green">Green</option>
                 </select>
</form>

<div id="results">
</div>

 

Plus you can see the new <div> above which has been added to receive the results of the request. And finally the PHP script:

 

<?php
$xml = simplexml_load_file('inventory.xml');

function xmlfilter ($xml, $color)
{
    $res = array();
    foreach ($xml->widget as $w)
    {
        $keep = 1;
        if ($color!='')
        {
            if ((string)$w->color != $color) $keep = 0;
        }
        if ($keep) $res[] = $v;
    }
    return $res;

$color = isset($_GET['color'])? $_GET['color'] : '';

    $filtered = xmlfilter($xml ,$color);
    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>";
}
}

?>

 

However, I no longer get any results from the PHP code. Did I hack it to pieces or remove something I shouldn't have?

Link to comment
Share on other sites

Its located in the JS file under function stateChanged():

 

var xmlHttp

function updateColor(str)
{ 
xmlHttp=GetXmlHttpObject()
if (xmlHttp==null)
{
alert ("Browser does not support HTTP Request")
return
} 
var url="ajaxFilter.php"
url=url+"?color="+str
xmlHttp.onreadystatechange=stateChanged 
xmlHttp.open("GET",url,true)
xmlHttp.send(null)
}

function stateChanged() 
{ 
if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
{ 
document.getElementById("results").innerHTML=xmlHttp.responseText 
} 
}

function GetXmlHttpObject()
{
var xmlHttp=null;

try
{
// Firefox, Opera 8.0+, Safari
xmlHttp=new XMLHttpRequest();
}
catch (e)
{
// Internet Explorer
try
  {
  xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
  }
catch (e)
  {
  xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
}
return xmlHttp;
}

Link to comment
Share on other sites

this code needs to be outside the function

 

$filtered = xmlfilter($xml ,$color);          // <------------- calls the function xmlfilter
    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>";
}

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.