Hi David.
This is the format string from a live feed.
xml|PRODUCTS/PRODUCT/RETAILER/
There are many fields/tags returned under the level "RETAILER" and sometimes, but not always there is one called "LINK".
Is there some way for Magic Parser to look for that specific field/tag and if it is missing ignore the whole record and move on to the next one printing out only those that do have it?
Thanks.
Thanks David,
I'll give it a go.
By the way Magic Parser has been running on one of my sites without a hitch for months now, excellent work!
Hi David,
I've been trying to add your recommended code
<?php
if (!isset($item["LINK"])) return;
?>
Can you help me to add it to this script please?
<?php
require("MagicParser.php");
if(!$_GET['page'])$page = 1;// If there is a current page number, use it.
else $page = $_GET['page'];//If there is no page number, set one!
$total_number_of_items = 0;//Count the total number of items in the xml feed
$items_per_page = 10;//Set the number of items displayed per page
$counter = 0;
function myRecordCounter($record)
{
global $total_number_of_items;
$total_number_of_items++;// increment for each record in the feed
}
function myRecordHandler($item)
{
global $page;
global $items_per_page;
global $counter;
$counter++;
// return false whilst parsing items on previous pages
if ($counter <= (($page-1)*$items_per_page)) return false;
//Enter the items to be displayed here as normal
print "<p>".$item["NAME"]."</p>";
print "<p>".$item["LINK"]."</p>";
print "<br>";
// return true if counter reaches current page * items on each page
return ($counter == ($page*$items_per_page));
}
//Print the table head tag
echo "<table class=\"content-text\" width=\"610\" border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\">";
//Parse the xml feeds
MagicParser_parse("http://my-url-goes-here","myRecordCounter");
MagicParser_parse("http://my-url-goes-here","myRecordHandler","xml|PRODUCTS/PRODUCT/RETAILER/");
//Print the table foot tag
echo "</table>";
$total_pages_count = ($total_number_of_items/$items_per_page);//Calculate the number of pages. Divide the total number of items by the number of items per page.
$total_number_of_pages = number_format($total_pages_count, 0);//Format the total number of pages so that decimals are not displayed
// display link to next page
echo"<p>";
//Display the current page number and the total number of pages
echo"<h1 align=\"center\">PAGE $page of $total_number_of_pages</h1>";
if ($page==1){
//If the page number is 1 only display the Page 2 link
echo "<h1 align=\"center\"><a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a></h1>";
}
else{
//If the page number is 2 or higher, display the previous page number and the next page number links
echo"<h1 align=\"center\"><a href='?page=".($page-1)."'><< PAGE ".($page-1)."</a> | <a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a></h1>";
}
echo"</p>";
print "Total Record: ".$total_number_of_items;
?>
Hi Dave,
With the code above, the first thing I noticed was that the call to MagicParser_parse when counting the records does not have a format string associated with it, so may not be parsing the same records as the second call.
Also, you will need to add the code to ignore the record if the LINK item is not set to both record handlers. I've made these modifications in the following copy of your code - see how you get on with this:
<?php
require("MagicParser.php");
if(!$_GET['page'])$page = 1;// If there is a current page number, use it.
else $page = $_GET['page'];//If there is no page number, set one!
$total_number_of_items = 0;//Count the total number of items in the xml feed
$items_per_page = 10;//Set the number of items displayed per page
$counter = 0;
function myRecordCounter($record)
{
global $total_number_of_items;
if (!isset($record["LINK"])) return;
$total_number_of_items++;// increment for each record in the feed
}
function myRecordHandler($item)
{
global $page;
global $items_per_page;
global $counter;
if (!isset($item["LINK"])) return;
$counter++;
// return false whilst parsing items on previous pages
if ($counter <= (($page-1)*$items_per_page)) return false;
//Enter the items to be displayed here as normal
print "<p>".$item["NAME"]."</p>";
print "<p>".$item["LINK"]."</p>";
print "<br>";
// return true if counter reaches current page * items on each page
return ($counter == ($page*$items_per_page));
}
//Print the table head tag
echo "<table class=\"content-text\" width=\"610\" border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\">";
//Parse the xml feeds
MagicParser_parse("http://my-url-goes-here","myRecordCounter","xml|PRODUCTS/PRODUCT/RETAILER/");
MagicParser_parse("http://my-url-goes-here","myRecordHandler","xml|PRODUCTS/PRODUCT/RETAILER/");
//Print the table foot tag
echo "</table>";
$total_pages_count = ($total_number_of_items/$items_per_page);//Calculate the number of pages. Divide the total number of items by the number of items per page.
$total_number_of_pages = number_format($total_pages_count, 0);//Format the total number of pages so that decimals are not displayed
// display link to next page
echo"<p>";
//Display the current page number and the total number of pages
echo"<h1 align=\"center\">PAGE $page of $total_number_of_pages</h1>";
if ($page==1){
//If the page number is 1 only display the Page 2 link
echo "<h1 align=\"center\"><a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a></h1>";
}
else{
//If the page number is 2 or higher, display the previous page number and the next page number links
echo"<h1 align=\"center\"><a href='?page=".($page-1)."'><< PAGE ".($page-1)."</a> | <a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a></h1>";
}
echo"</p>";
print "Total Record: ".$total_number_of_items;
?>
Notice how a different variable name is currently used in each case - $record in the counter record handler and $item in the main record handler - i've maintained this in the code above, but it is not necessary and you could use $record (or $item) in both cases for consistency.
Hope this helps!,
Cheers,
David.
Thanks David, that worked a treat.
I don't completely understand some of your comments. Can the code you just modified for me be simplified in any way or have you already done that?
Thanks.
Hi Dave,
Glad that's working. It can't really be simplified any more because of the requirement to display the total number of records. If you didn't need this, the initial parse to count the records could be removed - but if there's no problem with speed then I wouldn't worry about it!
Cheers,
David.
Hi David,
Just to complicate things, this is what I am now trying to do.
I now have two format strings
xml|PRODUCTS/PRODUCT/
xml|PRODUCTS/PRODUCT/RETAILER/
I have assumed that I had to have two separate recordhandler functions in order to retreive the two record sets as they are on different levels, one for product details and the other for the link details.
You already showed me how ignore the "RETAILER" records by using PHP's isset() function if the "LINK" field is not set. In this instance I also want the "PRODUCT" records to be ignored as well. Because the "PRODUCT" record set is on another level I don't even know if this can be done.
Basically, if the product doesn't have a link associated with it I want to ignore the whole record, subset and all.
Is this possible David?
Thanks.
Hi Dave,
It would be possible to do this, but requires a slight change in the way you handle the data with Magic Parser.
Normally, one would write code to process the record (i.e. load into a database) within the record handler function, which I think is what you're doing now. If, however, you are not sure whether you want to ignore the PRODUCT record at that time until you have looked at the RETALIER records then the trick is to copy the product data into an array, and then process the array later, in exactly the same way as you would have within myRecordHandler. Consider the following example:
<?php
function myProductRecordHandler($record)
{
global $product;
$product = $record;
}
function myRetailerRecordHandler($record)
{
global $ignore;
if (!isset($record["LINK"]))
{
$ignore = TRUE;
return;
}
// process RETAILER record as normal
}
$ignore = FALSE;
MagicParser_parse("http://my-url-goes-here","myProductRecordHandler","xml|PRODUCTS/PRODUCT/");
MagicParser_parse("http://my-url-goes-here","myRetailerRecordHandler","xml|PRODUCTS/PRODUCT/RETAILER/");
// check whether to ignore the product receord, process it if not:
if (!$ignore)
{
// now process $product just as if it was $record within myProductRecordHandler
}
?>
There's quite a bit going on here; but first this kind of pattern (and the previous examples in this thread) are only going to be valid if your feed obtained from your URL only contains one PRODUCT and then one or more RETAILERS. This is probably the case if you're making a single product query - in which case what i've described here will work fine. If your feed contains multiple PRODUCTS then a different approach is required, as you need to do all your processing within the PRODUCT record handler. If that's the case, let me know and I'll show you how to do that (it's quite easy to do with the way Magic Parser will resolve each of the RETAILER records for you).
Hope this helps!
Cheers,
David.
Hi David,
Thanks for that. It all makes sense but yes unfortunately the feed does contain multiple PRODUCTS (and as many RETAILERS as I choose) so it looks like I will need to do all the processing within the PRODUCT record handler. Would you show me how to do that as well then please?
It does take a number of seconds to return a large list of products and I could perhaps sort records in other ways so maybe I should be thinking about using a database later into my project.
Thanks
Hi Dave,
Is it possible for you to email me an example feed URL? That's the fastest way as I can just write a quick demo script for you. If you reply to your reg code or forum registration email is the easiest way to get me...
Cheers,
David.
Hi David,
I sent an example feed to your support email address. If you post some code would you leave out the url please.
Thanks.
Hi Dave,
Thanks for that. I'll email you directly with the same code.
Cheers,
David.
Hi David,
I've added pagination to the code you put together for me however its not quite working as I want it. The main problem is that if I set $items_per_page = 10 the code will usually diplay less because some of the records are being ignored (as there is no associated link).
Also, the "NEXT" button just keeps on going even if there are no records left. It would be better if the "NEXT" button were to disappear once the last record has been displayed.
The last thing is that $total_number_of_items seems to print the total number of records in the feed rather that the total record count post manipulation. Is it possible to print the total number of records post manipulation?
Could you help me with this please.
<?php
require("MagicParser.php");
if(!$_GET['page'])$page = 1;// If there is a current page number, use it.
else $page = $_GET['page'];//If there is no page number, set one!
$total_number_of_items = 0;//Count the total number of items in the xml feed
$items_per_page = 10;//Set the number of items displayed per page
$counter = 0;
function myRecordCounter($record)
{
global $total_number_of_items;
$total_number_of_items++; // increment for each record in the feed
}
function myRecordHandler($record)
{
global $page;
global $items_per_page;
global $counter;
$counter++;
// return false whilst parsing items on previous pages
if ($counter <= (($page-1)*$items_per_page)) return false;
$product = $record;
$retailers = array();
$i = 0;
while(1) {
if ($i) $postfix = "@".$i;
if (!isset($record["RETAILER".$postfix])) break;
// if this retailer has a LINK, extract the fields we want into an array...
if ($record["RETAILER".$postfix."/LINK"])
{
$retailer = array();
$retailer["NAME"] = $record["RETAILER".$postfix."/NAME"];
$retailer["LOGO"] = $record["RETAILER".$postfix."/LOGO"];
$retailer["LINK"] = $record["RETAILER".$postfix."/LINK"];
$retailer["PRICE"] = $record["RETAILER".$postfix."/PRICE"];
$retailer["MESSAGE"] = $record["RETAILER".$postfix."/MESSAGE"];
// ...and add the array to the array of retailers
$retailers[] = $retailer;
}
$i++;
}
// now we only want to process this product record if we have at least
// one retailer with a LINK...!
if (count($retailers))
{
// we do! so display the product information
print "<h2>".$product["NAME"]."</h2>";
print "<h2>".$product["DESCRIPTION"]."</h2>";
//// print "<h2>".$product["PRICES-URL"]."</h2>";
//print "<p>Available From:</p>";
// followed by the list of retailers
foreach($retailers as $retailer)
{
// print "<p><a href='".$retailer["LINK"]."'>".$retailer["NAME"]."</a> for <strong>".$retailer["PRICE"]."</strong></p>";
print "Message ".$retailer["MESSAGE"]."<p><a href='".$retailer["LINK"]."'>".$retailer["NAME"]."</a> for <strong>".$retailer["PRICE"]."</strong></p>";
}
}
return ($counter == ($page*$items_per_page));
}
$url = "MYURLHERE";
//MagicParser_parse($url,"myRecordHandler","xml|PRODUCTS/PRODUCT/");
//Print the table head tag
echo "<table class=\"content-text\" width=\"610\" border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\">";
//Parse the xml feeds
MagicParser_parse($url,"myRecordCounter","xml|PRODUCTS/PRODUCT/");
MagicParser_parse($url,"myRecordHandler","xml|PRODUCTS/PRODUCT/");
//Print the table foot tag
echo "</table>";
$total_pages_count = ($total_number_of_items/$items_per_page);//Calculate the number of pages. Divide the total number of items by the number of items per page.
$total_number_of_pages = number_format($total_pages_count, 0);//Format the total number of pages so that decimals are not displayed
// display link to next page
echo"<p>";
//Display the current page number and the total number of pages
echo"<h1 align=\"center\">PAGE $page of $total_number_of_pages</h1>";
if ($page==1){
//If the page number is 1 only display the Page 2 link
echo "<h1 align=\"center\"><a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a></h1>";
}
else{
//If the page number is 2 or higher, display the previous page number and the next page number links
echo"<h1 align=\"center\"><a href='?page=".($page-1)."'><< PAGE ".($page-1)."</a> | <a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a></h1>";
}
echo"</p>";
print "Total Records: ".$total_number_of_items;
?>
Hi Dave,
I've made 3 changes to the above code to make this work (see below for info)....
<?php
require("MagicParser.php");
if(!$_GET['page'])$page = 1;// If there is a current page number, use it.
else $page = $_GET['page'];//If there is no page number, set one!
$total_number_of_items = 0;//Count the total number of items in the xml feed
$items_per_page = 1;//Set the number of items displayed per page
$counter = 0;
function myRecordCounter($record)
{
global $total_number_of_items;
$have_valid_retailers = FALSE;
$i = 0;
while(1) {
if ($i) $postfix = "@".$i;
if (!isset($record["RETAILER".$postfix])) break;
// if this retailer has a LINK, extract the fields we want into an array...
if ($record["RETAILER".$postfix."/LINK"])
{
$have_valid_retailers = TRUE;
}
$i++;
}
if ($have_valid_retailers)
{
$total_number_of_items++; // increment for each record in the feed
}
}
function myRecordHandler($record)
{
global $page;
global $items_per_page;
global $counter;
$product = $record;
$retailers = array();
$i = 0;
while(1) {
if ($i) $postfix = "@".$i;
if (!isset($record["RETAILER".$postfix])) break;
// if this retailer has a LINK, extract the fields we want into an array...
if ($record["RETAILER".$postfix."/LINK"])
{
$retailer = array();
$retailer["NAME"] = $record["RETAILER".$postfix."/NAME"];
$retailer["LOGO"] = $record["RETAILER".$postfix."/LOGO"];
$retailer["LINK"] = $record["RETAILER".$postfix."/LINK"];
$retailer["PRICE"] = $record["RETAILER".$postfix."/PRICE"];
$retailer["MESSAGE"] = $record["RETAILER".$postfix."/MESSAGE"];
// ...and add the array to the array of retailers
$retailers[] = $retailer;
}
$i++;
}
// now we only want to process this product record if we have at least
// one retailer with a LINK...!
if (count($retailers))
{
$counter++;
// return false whilst parsing items on previous pages
if ($counter <= (($page-1)*$items_per_page)) return false;
// we do! so display the product information
print "<h2>".$product["NAME"]."</h2>";
print "<h2>".$product["DESCRIPTION"]."</h2>";
//// print "<h2>".$product["PRICES-URL"]."</h2>";
//print "<p>Available From:</p>";
// followed by the list of retailers
foreach($retailers as $retailer)
{
// print "<p><a href='".$retailer["LINK"]."'>".$retailer["NAME"]."</a> for <strong>".$retailer["PRICE"]."</strong></p>";
print "Message ".$retailer["MESSAGE"]."<p><a href='".$retailer["LINK"]."'>".$retailer["NAME"]."</a> for <strong>".$retailer["PRICE"]."</strong></p>";
}
}
return ($counter == ($page*$items_per_page));
}
$url = "MYURLHERE";
//MagicParser_parse($url,"myRecordHandler","xml|PRODUCTS/PRODUCT/");
//Print the table head tag
echo "<table class=\"content-text\" width=\"610\" border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\">";
//Parse the xml feeds
MagicParser_parse($url,"myRecordCounter","xml|PRODUCTS/PRODUCT/");
MagicParser_parse($url,"myRecordHandler","xml|PRODUCTS/PRODUCT/");
//Print the table foot tag
echo "</table>";
$total_pages_count = ($total_number_of_items/$items_per_page);//Calculate the number of pages. Divide the total number of items by the number of items per page.
$total_number_of_pages = number_format($total_pages_count, 0);//Format the total number of pages so that decimals are not displayed
// display link to next page
echo "<p>";
//Display the current page number and the total number of pages
echo "<h1 align=\"center\">PAGE $page of $total_number_of_pages</h1>";
echo "<h1 align=\"center\">";
if ($page==1){
//If the page number is 1 only display the Page 2 link
echo "<a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a></h1>";
}
else {
//If the page number is 2 or higher, display the previous page number and the next page number links
echo "<a href='?page=".($page-1)."'><< PAGE ".($page-1)."</a>";
}
if($page < $total_pages_count) {
//If the page number is less than total pages display the next page number
echo "| <a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a>";
}
echo"</h1>";
echo"</p>";
print "Total Records: ".$total_number_of_items;
?>
To make it work properly, first I added the same "ignore" logic to the record counter. This is why the counts were mis-matched. Secondly, the main record handler needed to count records only when there was one to display - so I moved the $count++ etc. code lower down to where you display the record.
Finally, to make the links work I added a case to only display the Next link if we are on a page less than total_pages_count....
Hope this helps!
Cheers,
David.
Hi David,
I made some minor changes to the above code and it is great for queries such as "Dyson" but a more specific query such as "Dyson DC14 Animal" only returns a single retailer when there are actually about 37.
The solution I have come up with is to run another recordhandler function (that I have prepared) if $total_number_of_items==1.
Can you show me how to integrate/do this with the following, updated code please.
<?php
require("MagicParser.php");
if(!$_GET['page'])$page = 1;// If there is a current page number, use it.
else $page = $_GET['page'];//If there is no page number, set one!
$total_number_of_items = 0;//Count the total number of items in the xml feed
$items_per_page = 7;//Set the number of items displayed per page
$counter = 0;
function myRecordCounter($record)
{
global $total_number_of_items;
$have_valid_retailers = FALSE;
$i = 0;
while(1) {
if ($i) $postfix = "@".$i;
if (!isset($record["RETAILER".$postfix])) break;
// if this retailer has a LINK, extract the fields we want into an array...
if ($record["RETAILER".$postfix."/LINK"])
{
$have_valid_retailers = TRUE;
}
$i++;
}
if ($have_valid_retailers)
{
$total_number_of_items++; // increment for each record in the feed
}
}
function myRecordHandler($record)
{
global $total_number_of_items;
global $page;
global $items_per_page;
global $counter;
$product = $record;
$retailers = array();
$i = 0;
while(1) {
if ($i) $postfix = "@".$i;
if (!isset($record["RETAILER".$postfix])) break;
// if this retailer has a LINK, extract the fields we want into an array...
if ($record["RETAILER".$postfix."/LINK"])
{
$retailer = array();
$retailer["NAME"] = $record["RETAILER".$postfix."/NAME"];
$retailer["LOGO"] = $record["RETAILER".$postfix."/LOGO"];
$retailer["LINK"] = $record["RETAILER".$postfix."/LINK"];
$retailer["PRICE"] = $record["RETAILER".$postfix."/PRICE"];
$retailer["MESSAGE"] = $record["RETAILER".$postfix."/MESSAGE"];
// ...and add the array to the array of retailers
$retailers[] = $retailer;
}
$i++;
}
// now we only want to process this product record if we have at least
// one retailer with a LINK...!
if (count($retailers))
{
$counter++;
// return false whilst parsing items on previous pages
if ($counter <= (($page-1)*$items_per_page)) return false;
// we do! so display the product information
print "<h2>".$product["NAME"]."</h2>";
print "<h2>".$product["DESCRIPTION"]."</h2>";
//// print "<h2>".$product["PRICES-URL"]."</h2>";
//print "<p>Available From:</p>";
// followed by the list of retailers
foreach($retailers as $retailer)
{
// print "<p><a href='".$retailer["LINK"]."'>".$retailer["NAME"]."</a> for <strong>".$retailer["PRICE"]."</strong></p>";
print "Message ".$retailer["MESSAGE"]."<p><a href='".$retailer["LINK"]."'>".$retailer["NAME"]."</a> for <strong>".$retailer["PRICE"]."</strong></p>";
}
}
return ($counter == ($page*$items_per_page));
}
$url = "MYURLHERE";
//MagicParser_parse($url,"myRecordHandler","xml|PRODUCTS/PRODUCT/");
//Print the table head tag
echo "<table class=\"content-text\" width=\"610\" border=\"1\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\">";
//Parse the xml feeds
MagicParser_parse($url,"myRecordCounter","xml|PRODUCTS/PRODUCT/");
MagicParser_parse($url,"myRecordHandler","xml|PRODUCTS/PRODUCT/");
if (!$total_number_of_items)
{
print "<p align=\"center\">Sorry, no results found.</p>";
}
//Print the table foot tag
echo "</table>";
$total_pages_count = ceil($total_number_of_items/$items_per_page);// Calculate number of pages. Dividing total items by total items per page and round result up to nearest whole number (i.e 4.2 becomes page 5).
// display link to next page
echo "<p>";
echo "<h1 align=\"center\">PAGE $page of $total_pages_count </h1>";
echo "<h1 align=\"center\">";
if ($total_number_of_items < $items_per_page)
{
//If total items is less than items per page show no buttons
echo "show nothing";
}
if ($total_number_of_items == $items_per_page)
{
//If total items is equal to items per page show no Next or Previous links/buttons
//echo "show nothing";
}
elseif ($page==1){
//If the page number is 1 just display the page 2 link
echo "<h1 align=\"center\"><a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a></h1>";
}
elseif ($page == $total_pages_count)
{
//If the page number is equal to total pages display just the previous page link
echo "<h1 align=\"center\"><a href='?page=".($page-1)."'>PAGE ".($page-1)." << </a></h1>";
}
else
{
//If the page number is 2 or higher, display the previous page number and the next page number links
echo"<h1 align=\"center\"><a href='?page=".($page-1)."'><< PAGE ".($page-1)."</a> | <a href='?page=".($page+1)."'>PAGE ".($page+1)." >></a></h1>";
}
echo"</h1>";
echo"</p>";
print "Total Records: ".$total_number_of_items;
?>
Thanks, Dave.
Hi Dave,
The logical place to insert your new code would be with the following section:
if (!$total_number_of_items)
{
print "<p align=\"center\">Sorry, no results found.</p>";
}
...for example, if you change this as follows:
if (!$total_number_of_items)
{
print "<p align=\"center\">Sorry, no results found.</p>";
}
elseif($total_number_of_items == 1)
{
MagicParser_parse($url,"yourNewRecordHandler","xml|PRODUCTS/PRODUCT/");
}
Note the name of the record handler - "yourNewRecordHandler" - simply modify that to whatever you have called your new record handler...
Hope this helps!
Cheers,
David.
Hi Dave,
You can do this quite easily within your record handler function by using PHP's isset() function. If it's not set, return from the record handler to effectively ignore the record; for example:
<?php
function myRecordHandler($record)
{
if (!isset($record["LINK"])) return;
// ...rest of function...
}
?>
Hope this helps,
Cheers,
David.