PHP xpath Error in foreach() Statement [duplicate] - php

This question already has answers here:
SimpleXML: Selecting Elements Which Have A Certain Attribute Value
(2 answers)
Closed 8 years ago.
I am trying to build a basic shopping cart using only PHP and XML. I have chosen to use simplexml and xpath here. Items are added fine, but when it comes to the "getProduct($id)" method, which will return the product with a matching code, I am faced with the following error:
Warning: Invalid argument supplied for foreach() in
/srv/disk6/1664324/www/mattc.biz.ht/cart.php on line 203
Here is a snippet from my XML (For the Structure)
<?xml version="1.0" encoding="utf-8"?>
<GreenTrade>
<brand id="Alara">
<product code="1">
<name>Fair Trade Muesli x 500g</name>
<desc>Piced with cinnamon and honey</desc>
<image>1.jpg</image>
</product>
<product code="2">
<name>Luxury Gluten Free Muesli x 500g</name>
<desc>Gluten Free - Wheat Free - High Proteins (Over 10 Percent) - Balanced Nutrition - Vegan </desc>
<image>luxuryglutenfree.jpg</image>
</product>
<product code="3">
<name>Of the Earth - Goji berries x 60g</name>
<desc>Bursting with Beta-Carotene and all 8 Essential Amino Acids </desc>
<image>gojiberries.jpg</image>
</product>
</brand>
<brand id = "BigOz">
<product code="5">
<name>Corn Flakes x 350g</name>
<desc> Gluten Free – Dairy free – Low in Sodium – No added artificial flavours, colours or preservatives – Naturally cholesterol and sodium free </desc>
<image>5.jpg</image>
</product>
</brand>
<brand id="Windmill">
<product code="8">
<name>Amisa Organic Corn and Rice Rigatoni</name>
<desc>Organic, Gluten Free, Dairy Free, Wholegrain</desc>
<image>corn_rice_rigatoni.jpg</image>
</product>
</brand>
</GreenTrade>
And here is my PHP / HTML. For some reason I was not allowed to add PHP tags so i put where they would be in comments. The page would be accessed from a URL Such as:
http://www.mattc.biz.ht/cart.php?action=add&item=4 (Actual Site)
<body>
<div class="container">
<div class="header"><img src="Mattc.fw.png" alt="Insert Logo Here" name="Insert_logo" width="180" height="90" id="Insert_logo" style="background-color: #C6D580; display:block;" />
<!-- end .header --></div>
<div class="sidebar1">
<ul class="nav">
<li>Home</li>
<li>Store</li>
<li>Cart</li>
<li>Email</li>
</ul>
<p>Left Side Bar</p>
<!-- end .sidebar1 --></div>
<div class="content">
<h1>Your Shopping Cart</h1>
//OPEN PHP TAG
$xml = simplexml_load_file('GreenTrade.xml');
$brands = $xml->xpath('//brand');
$prodz = $xml->xpath('//product');
$product_id = $_GET [item];
$action = $_GET [action];
//$contains = $_SESSION['my_cart'];
$brandz = 3;
//Adds 1 to QTY
if (!empty($_GET['item']) && $action == "add") {
$_SESSION['cart'][$product_id]++;
}
//Delete 1 From QTY
if (!empty($_GET['item']) && $action == "del") {
$_SESSION['cart'][$product_id]--;
if($_SESSION['cart'][$product_id] <= 0){
unset($_SESSION['cart'][$product_id]);
}
}
if ($action == "empty") {
unset($_SESSION['cart']);
}
echo '</br><hr align="CENTER">';
if($_SESSION['cart']){
echo "<div align='center'><a href='cart.php?action=empty'>Empty Cart</a></div>";
foreach($_SESSION['cart'] as $prd => $quantity){
$product=getProduct($prd); //<--- Call to getProduct
echo "Name: " . $product->name . '</br>';
echo "Description: " . $product->desc . '</br>';
echo '<img src=' . $product->image . ' >' . '</br>';
echo "Ordered: " . $quantity . '</br>';
echo 'Add Another' . '</br>';
echo 'Remove One' . '</br>';
echo '</br><hr align="CENTER">';
}
} else {
echo '<h2>'."Your Cart Is Empty".'</h2>';
}
//VVV Here Is the Troublesome Function VVV
function getProduct($id){
foreach($prodz as $prod){
if($prod['code'] == $id){
return $prod;
}
}
}
// CLOSE PHP TAG
<!-- end .content --></div>
<div class="footer">
<p>MattC.biz.ht (C) Matthew Cassar 2014</p>
<p>A Chris Porter Web Project <!-- end .footer --></p>
</div>
<!-- end .container --></div>
</body>

The array must be passed as a paramter because $prodz is out of scope (compare: PHP variable scope.
function getProduct(array $products, $id)
{
foreach ($products as $product) {
if ($product['code'] == $id) {
return $product;
}
}
}

Related

How can print node value XML in an orderly way PHP

I have a XML like this:
<description>
<heading id="01"> Math </heading>
<p id="01"> Text 1 </p>
<heading id="02"> History </heading>
<p id="02"> Text 2</p>
<p id="03"> Text 3</p>
<heading id="03"> Biology </heading>
<p id="04"> Text 4 </p>
</description>
I also have many xml files have structure like this one, they are only different from amount of <p> node of every <heading> node.
How can I print <heading> and some <p> node and the second heading....
I tried to use foreach, but it's not true.
my code:
<?php
$xml=simplexml_load_file("NWB2.xml") or die("Error: Cannot create object");
echo "<b>".$xml->{'description'}->{'heading'}."</b>";
echo "<p>".$xml->{'description'}->{'p'}."</p>";
?>
If it's just a case of having different style depending on the input tag, you can use a foreach() loop and output the value according to the tag type...
$xml=simplexml_load_file("NWB2.xml") or die("Error: Cannot create object");
foreach ( $xml as $type => $value ) {
if ($type == "p") {
echo $value;
}
else {
echo "<b>$value</b>";
}
}

Looping through multiple images in xml file with php code

Below is my PHP code and XML file, I have been trying with so many different echos to loop through my images in my XML file to display each image to correct product but can only display the first image to all three products.
XML code:
<my_products>
<product>
<id>1</id>
<image> csuT.jpg</image>
<name>Champion T-Shirt</name>
<price>18.00</price>
<description>
Get the perfect look to let everyone know you are a stylish fan!
</description>
</product>
<product>
<id>2</id>
<image> webBook.jpg</image>
<name>C# Programming: Analysis to Program Design</name>
<price>192.00</price>
<description>
Your hands-on guide to Microsoft Visual C# fundamentals with Visual Studio 2017
</description>
</product>
<product>
<id>3</id>
<image> calcPic.jpg</image>
<name>Calculator TI-BAII Plus 10DIG/24CASH</name>
<price>39.00</price>
<description>
Performs common math as well as various financial functions
</description>
</product>
</my_products>
PHP code:
$xml = simplexml_load_file($file);
$script_images="";
$script_products="";
$script_product_prices="";
//Loop through the products defined in the products.xml file
foreach ($xml->product as $r)
{
$script_images.="products[".($r->id)."]=\"".($r->image)."\";\n";
$script_products.="products[".($r->id)."]=\"".($r->name)."\";\n";
$script_product_prices.="product_prices[".($r->id)."]=\"".($r->price)."\";\n";
?>
<div>
<p class="lead">
<h3 class="pull-right no-top-margin"><?php echo $currency_symbol;?><?php echo $r->price;?></h3>
<h3><?php echo "<image src='csuT.jpg' 'calcPic.jpg' 'webBook.jpg'/>";?></h3>
</p>
<h3><?php echo $r->name;?></h3>
</p>
<p>
<?php echo $r->description;?>
</p>
<br/>
<?php
//If there is details link set for the product, show a Details button
if(trim($r->details_link)!="")
{
?>
<a target="_blank" href="http://<?php echo str_replace("http://","",trim($r->details_link));?>"</a>
<?php
}
?>
<a class="btn btn-xs btn-info" href="javascript:AddToCart(<?php echo $r->id;?>)">Add to Cart</a>
</div>
<hr/>
<?php
}
?>
<script>
var currency_symbol="<?php echo $currency_symbol;?>";
var products=Array();
<?php echo $script_images;?>
var product_images=Array();
<?php echo $script_products;?>
var product_prices=Array();
<?php echo $script_product_prices;?>
</script>
You just need to extract the image from the XML (the same way as done for the Javascript) and I've added a trim() to remove any spaces round the field...
<h3><?php $image = trim($r->image);
echo "<image src='$image'/>";?></h3>
Also add trim to...
$script_products.="products[".($r->id)."]=\"".($r->name)."\";\n";
What is this? :
<h3><?php echo "<image src='csuT.jpg' 'calcPic.jpg' 'webBook.jpg'/>";?></h3>
your src attribute is static and you must change it

Output items from XML feed when matching to category

I've exported all product items from my shop as an XML-File and parsed these items with PHP in my single.php of my theme. The parse works fine so far.
Now i want to only display products which category name matches with the ones that have been set in the article editor of WP. This is my code:
<?php
// Parse XML Feed
$html = "";
$url = "http://example.com/feed.xml";
$xml = simplexml_load_file($url);
$item = $xml->channel->item;
$categories = get_the_category();
for($i = 0; $i < count($item); $i++){
$title = $item[$i]->title;
$link = $item[$i]->link;
$category = $item[$i]->category;
$img = $item[$i]->description->a->img["src"];
// This approach breaks my site. A loop in another loop seems not to be that good
// foreach ($categories as $i => $cat) {
// $catName = $cat->name;
// if (preg_match("/\b$catName\b/", $category)) {
// $html .= "
// <a href='$link'><h3>$title</h3>
// <img src='$img'>
// <p>$category</p></a>
// <hr>";
// }
// }
if (preg_match("/\bCATEGORY_NAME\b/", $category)) {
$html .= "
<a href='$link'><h3>$title</h3>
<img src='$img'>
<p>$category</p></a>
<hr>";
}
}
echo $html;
?>
If i change CATEGORY_NAME to an category name which exits, then the output works like i want. The other approach with that loop breaks my site with an "Fatal error: Allowed memory size of *** bytes exhausted…".
Would love to hear some tips
EDIT: Here is some example code
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<atom:link href="www.example.com/export.xml" rel="self" type="application/rss+xml" />
<title>www.example.com</title>
<description>desc</description>
<link>www.example.com</link>
<language>1-1</language>
<image>
<url>www.example.com/logo.gif</url>
<title>test page</title>
<link>http://example.com</link>
</image>
<item>
<title>Example item</title>
<guid>www.example.com/item</guid>
<link>www.example.com/item</link>
<description>
<a href="www.example.com/item" style="border:0 none;">
<img src="www.example.com/image.png" align="right" style="padding: 0pt 0pt 12px 12px; float: right;" />
</a>
</description>
<category>Categoryname</category>
<pubDate>Thu, 24 Aug 2017 17:19:17 +0200</pubDate>rn</item>
</channel>
</rss>

How to read all nodes of a XML file with more than three nodes levels using PHP?

I am currently writing a PHP script to read all nodes of a XML file with more than three node levels (depth > 2). However I only could read accurately upto first level child.
I would highly appreciate, if you could let me know the error I have made while I am trying to read second level child nodes.
My xml file
<?xml version="1.0" encoding="utf-8"?>
<document nipperstudio="2.3.10.3500" xmlversion="2" xmlrevision="3">
<report>
<part index="1" title="Your Report" ref="YOURREPORT">
<section index="1.1" title="Introduction" ref="INTRODUCTION">
<text>Inside the section 1.1.:</text>
<list type="bullet">
<listitem>detailed description of list item 01;</listitem>
<listitem>detailed description of list item 02;</listitem>
</list>
</section>
<section index="1.2" title="Report Conventions" ref="REPORTCONVENTIONS">
<text>This report makes use of the text conventions.</text>
<table index="3" title="Report text conventions" ref="REPORTTEXTCONVENTIONS">
<headings>
<heading>Convention</heading>
<heading>Description</heading>
</headings>
</table>
</section>
</part>
<part index="2" title="Security Audit" ref="SECURITYAUDIT">
<section index="2.1" title="Introduction" ref="INTRODUCTION">
<text>Inside the section 2.1.:</text>
<list type="bullet">
<listitem>detailed description of list item 01;</listitem>
<listitem>detailed description of list item 02;</listitem>
</list>
<section index="2.1.1" title="Issue Overview" ref="ISSUEOVERVIEW">
<text>Inside the section 2.1.1</text>
<text title="Issue Finding">The is the body text of 2.1.1.</text>
</section>
<section index="2.1.2" title="Rating Overview" ref="RATINGSYSTEM">
<text>Inside the section 2.1.1</text>
<text title="Issue Finding">The is the body text of 2.1.1.</text>
</section>
</section>
<section index="2.2" title="section title" ref="SECTION2.2">
<section index="2.2.1" title="Finding" ref="FINDING">
<text>Inside the section 2.2.1</text>
<text title="Issue Finding">The is the body text of 2.2.1.</text>
</section>
</section>
</part>
</report>
</document>
My PHP Script is given below.
Test XML Reader
<html>
<title>Test XML Reader</title>
<body>
<p>Output from xmlreader</p>
<?php
readXmlFiles();
?>
</body>
</html>
<?php
function readXmlFiles(){
// create the reader object
$reader = new XMLReader();
// reader the XML file.
$reader->open("./fwxml/03.xml"); //open the xml file to read.
while($reader->read()) {
switch($reader->nodeType) {
case (XMLREADER::ELEMENT):
if ($reader->localName == 'report') { //read the local name of the node
$node = $reader->expand();
$dom = new DomDocument();
$n = $dom->importNode($node,true);
$dom->appendChild($n);
foreach(($dom->getElementsByTagName('part')) as $fwpart) {
$parttitle = $fwpart->getAttribute('title');
echo "=====".$parttitle."=====<br>";
foreach(($fwpart->childNodes) as $cnode){
if($cnode->nodeName == 'section'){
$index = $cnode->getAttribute('index');
$title = $cnode->getAttribute('title');
$ref = $cnode->getAttribute('ref');
echo "Index = " .$index."<br>";
echo "Title = " .$title."<br>";
echo "Ref = " .$ref."<br>";
$fwsec = $dom->getElementsByTagName('section');
echo $fwsec->item(0)->nodeValue."<br>";
echo "<br><br><br>";
}//end of if
}//end of foreach
}
}
break; //end of XMLREADER::ELEMENT
case (XMLREADER::END_ELEMENT):
// do something based on when the element closes.
break;
}
}
} //end of function
?>

Why is my recursive loop creating too many children?

I'm using a PHP recursive loop to parse through an XML document to create a nested list, however for some reason the loop is broken and creating duplicates of elements within the list, as well as blank elements.
The XML (a list of family tree data) is structured as follows:
<?xml version="1.0" encoding="UTF-8"?>
<family>
<indi>
<id>id1</id>
<fn>Thomas</fn>
<bday></bday>
<dday></dday>
<spouse></spouse>
<family>
<indi>
<id>id1</id>
<fn>Alexander</fn>
<bday></bday>
<dday></dday>
<spouse></spouse>
<family>
</family>
</indi>
<indi>
<id>id1</id>
<fn>John</fn>
<bday></bday>
<dday></dday>
<spouse></spouse>
<family>
<indi>
<id>id1</id>
<fn>George</fn>
<bday></bday>
<dday></dday>
<spouse></spouse>
<family>
</family>
</indi>
</family>
</indi>
</family>
</indi>
</family>
And here's my PHP loop, which loads the XML file then loops through it to create a nested ul:
<?php
function outputIndi($indi) {
echo '<li>';
$id = $indi->getElementsByTagName('id')->item(0)->nodeValue;
echo '<span class="vcard person" id="' . $id . '">';
$fn = $indi->getElementsByTagName('fn')->item(0)->nodeValue;
$bday = $indi->getElementsByTagName('bday')->item(0)->nodeValue;
echo '<span class="edit fn">' . $fn . '</span>';
echo '<span class="edit bday">' . $bday . '</span>';
// ...
echo '</span>';
echo '<ul>';
$family = $indi->getElementsByTagName('family');
foreach ($family as $subIndi) {
outputIndi($subIndi);
}
echo '</ul></li>';
}
$doc = new DOMDocument();
$doc->load('armstrong.xml');
outputIndi($doc);
?>
EDIT here's the desired outcome (nested lists, with ul's signifying families and li's signifying individuals)
<ul>
<li>
<span class="vcard">
<span class="fn">Thomas</span>
<span class="bday"></span>
<span class="dday"></span>
<ul>
... repeat for all ancestors ...
</ul>
<li>
<ul>
You can see the output at http://chris-armstrong.com/gortin . Any ideas where I'm going wrong? I think it's something to do with the $subIndi value, but anytime I try and change it I get an error. Would really appreciate any help!
Sounds perfect! Could you give me an
example? Does this mean I can save the
data as XML, then load it in as nested
ul's?
Yes, you can do exactly that. Here's an XSL which renders nested UL's:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>Family tree</h2>
<ul>
<li><xsl:value-of select="indi/fn" /></li>
<!-- apply-templates will select all the indi/family nodes -->
<xsl:apply-templates select="indi/family" />
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="family">
<ul>
<li>
<div>
<xsl:value-of select="id" />: <xsl:value-of select="fn" />
(<xsl:variable name="bday" select="bday" />
to
<xsl:variable name="dday" select="dday" />)
</div>
</li>
<!-- This node matches the 'family' nodes, and we're going to apply-templates on the inner 'family' node,
so this is the same thing as recursion. -->
<xsl:apply-templates select="family" />
</ul>
</xsl:template>
</xsl:stylesheet>
I don't know php, but this article will show you how to transform XML using the style sheet above.
You can also link your style sheet by adding a stylesheet directive at the top of your XML file (see for an example).
getElementsByTagName will give you all nodes, not just immediate children:
$family = $indi->getElementsByTagName('family');
foreach ($family as $subIndi) {
outputIndi($subIndi);
}
You will call outputIndi() for grand children, etc repeatedly.
Here is an example (from another stackoverflow question):
for ($n = $indi->firstChild; $n !== null; $n = $n->nextSibling) {
if ($n instanceof DOMElement && $n->tagName == "family") {
outputIndi($n);
}
}
Replace this
$family = $indi->getElementsByTagName('family');
foreach ($family as $subIndi) {
outputIndi($subIndi);
}
by this
if(!empty($indi))
foreach($indi as $subIndi){
outputIndi($subIndi);
}
I realize
if($indi->hasChildNodes())
is better than
if(!empty($indi))

Categories