So here is the deal:
I have an array that contains manufacturers' names for smartphones and an XML file that holds specifications for each specific phone.
What I am trying to do is to group phones based on manufacturer. I am using nested FOREACH loop to do this. And here is my code:
foreach ($makes as $manufacturer){
echo '<div>'.'<h2>'.$manufacturer.'</h2>'.'<hr>';
foreach ($xml as $item){
if($item->make == $manufacturer){
$src = $item->thumb;
echo '<div>'."<img src='$src' width='100'/>".'<h1>'.
$item->make.' '.$item->model.'</h1>'.'</div>';
}
}
echo '</div>';
}
The problem with this approach is that for some reason my page displays ONLY THE FIRST phone for every manufacturer, instead of going through every model.
What am I doing wrong here?
Here is XML sample:
<?xml version="1.0" encoding="utf-8"?>
<items>
<item>
<make></make>
<model></model>
<thumb></thumb>
</item>
</items>
Also, if I remove outer loop, code works perfectly and displays every phone from the XML
You have a typo:
echo '<div>'."<img src='$src' width='100'/>".'<h1>'.
$item->make.' '.$item->model.'</h1>'.
should be
echo '<div>'."<img src='$src' width='100'/>".'<h1>'.
$item->make.' '.$item->model.'</h1>';
Note the ";" at the end of the echo.
Related
I try to get domain name from Plesk API result XML data as below:
<packet version="1.6.7.0">
<site-alias>
<get>
<result>
<status>ok</status>
<info>
<name>example.com</name>
</info>
</result>
<result>
<status>ok</status>
<info>
<name>domain.net</name>
</info>
</result>
</get>
</site-alias>
</packet>
using
$xml= simplexml_load_string($response);
echo $xml['site-alias']['get']['result'][0]['name'];
if there is more better way to do so, please advice, thanks.
There are multiple ways to get the values using SimpleXMLElement.
To get only 1 value, you could for example do it like this:
// Get 1 using SimpleXMLElement
echo $xml->{"site-alias"}->get->result->info->name;
// Get 1 using xpath
echo $xml->xpath('/packet/site-alias/get/result[1]/info/name')[0];
To get multiple values you could do it like this:
// Get multiple using SimpleXMLElement
$items = $xml->{"site-alias"}->get->result;
foreach ($items as $item) {
echo $item->info->name . "<br>";
}
// Get multiple using xpath
$items = $xml->xpath('/packet/site-alias/get/result/info/name');
foreach ($items as $item) {
echo $item . "<br>";
}
The SimpleXMLElement has a method __toString so you can echo the string content.
The xpath method returns an array, so you can get the first value using index 0.
A short way to get your value could be:
echo $xml->xpath('//name')[0];
Demo
I have the following xml doc:
<shop id="123" name="xxx">
<product id="123456">
<name>Book</name>
<price>9.99</price
</product>
<product id="789012">
<name>Perfume</name>
<price>12.99</price
</product>
<product id="345678">
<name>T-Shirt</name>
<price>9.99</price
</product>
</shop>
<shop id="456" name="yyy">
<product id="123456">
<name>Book</name>
<price>9.99</price
</product>
</shop>
I have the following loop to gather the information for each product:
$data_feed = 'www.mydomain.com/xml/compression/gzip/';
$xml = simplexml_load_file("compress.zlib://$data_feed");
foreach ($xml->xpath('//product') as $row) {
$id = $row["id"]; // product id eg. "123456"
$name = $row->name;
$price = $row->price;
// update database etc.
}
HOWEVER, I also want to gather the information for each product's parent shop ("id" and "name").
I can easily change my xpath to start from shop as opposed to product, but I'm unsure of the most efficient way to then construct an additional loop within my foreach to loop each indented product
Make sense?
I'd go without xpath and just use two nested foreach-loops:
$xml = simplexml_load_string($x); // assume XML in $x
foreach ($xml->shop as $shop) {
echo "shop $shop[name], id $shop[id] <br />";
foreach ($shop->product as $product) {
echo "- $product->name (id $product[id]), $product->price <br />";
}
}
see it working: http://codepad.viper-7.com/vFmGvY
BTW: your XML is broken, probably a typo. Each closing </price> is missing its last >.
Sure, makes sense, you want one iteration, not a nested product of iterations (albeit that won't cut you much, #michi showed already), which is possible as well:
foreach ($xml->xpath('//product') as $row)
{
$id = $row["id"]; // product id eg. "123456"
$name = $row->name;
$price = $row->price;
$shopId = $row->xpath('../#id')[0];
$shopName = $row->xpath('../#name')[0];
// update database etc.
}
As this example shows, you can run xpath() on each element-node and the context-node is automatically set to the node itself, therefore the realtive path .. in xpath works to access the parent element (see as well: Access an element's parent with PHP's SimpleXML?). Of that then both attributes are read and then via PHP 5.4 array de-referencing the first (and only) attribute is accessed.
I hope this helps and shed some light how it works. Your question reminds me a bit of an earlier one where I suggested some kind of generic solution to these kind of problems:
Answer to Combining two Xpaths into one loop?
XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<lessons>
<lesson level="1" course="2">
<name type="Dog" category="Animals">Dog name</name>
</lesson>
</lessons>
I want to get the values saved like this:
$type = "Dog";
$category = "Animals";
$name = "dog name";
This is what I've done:
foreach($xml->name as $name){
$type = $name['type'];
$category = $name['category'];
echo "Type: $type Category: $category<br>";
// AND TO get the text, haven't figuered it out yet.. <name ..="" ..="">text</name>
}
But it doesn't work. Don't get any errors neither any output. Any ideas?
EDIT:
OK. I changed foreach($xml->name as $name)
to foreach($xml->lesson->name as $name)
so I get the values of the attribute. But now I don't know how to get the value of the children.
I've tried this: $xml->lesson->children()
It prints children()
SOLVED: $text = $xml->lesson->children();
echo $text;
PROBLEM WAS: I'm using utf-8 in my other code but didn't change it.
Edit : this part related to a question typo. If you copied your xml directly from where you were editting it, then part of the problem might be that it is malformed. You have an opening <lessons> but you appear to wrongly try to close it with </lesson>.
Also, depending on your root node settings, ->name may or may not be a child of the $xml object. Can you post a var_dump() of it and get some clues?
I think, there is some problem in your xml.
-> You have to close lessons tag correctly.Because you have entered </lesson> (see last line) instead of </lessons>. If you start any tag, you should use the same tag name while closing..
you can use this code to extract values from your xml,
<?php
$xmlstring='<lessons>
<lesson level="1" course="2">
<name type="Dog" category="Animals">Dog name</name>
</lesson>
</lessons>';
$xml = simplexml_load_string($xmlstring);
$ATTRIBUTE=array();
$counter = 0;
foreach($xml->children() as $key=>$child)
{
$counter++;
$ATTRIBUTE[$counter]["type"]=$child->name->attributes()->type;
$ATTRIBUTE[$counter]["category"]=$child->name->attributes()->category;
$ATTRIBUTE[$counter]["value"]= $child->name;
}
echo "<pre>";
print_r($ATTRIBUTE);
?>
here you will get everything in array. So you can fetch based on your requirement.
Im trying to parse an XML document using the XPath element in simple XML. However this script below (When searching for the entry "U2" in the last.fm API) returns:
Passengers Passengers Bono Passengers Bono U2 and Green Day Passengers
Bono U2 and Green Day R.E.M. Passengers Bono U2 and Green Day R.E.M.
INXS
As you can see there are repeating nodes. Is there a way that I can stop duplicate/repeating nodes from being shown?
(PHP Code)
$xmlmusic = new SimpleXMLElement($result);
$releases = $xmlmusic->xpath('artist/similar/artist');
foreach ($releases as $artist) {
$artistResult .= $artist->name . PHP_EOL;
echo $artistResult;}
(XML Document)
<?xml version="1.0" encoding="utf-8"?>
<lfm status="ok">
<artist>
<name>U2</name>
<mbid>704acdbb-1415-4782-b0b6-0596b8c55e46</mbid>
<url>http://www.last.fm/music/U2</url>
<image size="small">http://userserve-ak.last.fm/serve/34/107345.jpg</image>
<streamable>1</streamable>
<stats>
<listeners>2613654</listeners>
<playcount>96947986</playcount>
</stats>
<similar>
<artist>
<name>Passengers</name>
<url>http://www.last.fm/music/Passengers</url>
<image size="small">http://userserve-ak.last.fm/serve/34/4826014.jpg</image>
</artist>
I'm assuming that your XML snippet is only a small sample of the full results, so...
you need to modify your foreach loop to check if the artist currently being processed has been seen before. The easiest way is to use an array:
$seen = array();
foreach ($releases as $artist) {
if (!isset($seen[$artist->name])) {
$seen[$artist->name] = true;
}
}
Once the loop's done, you've got a nice array with each artist being a key in $seen. To replicate your simple string concatenation, you simply implode/echo:
echo implode(array_keys(', ', $seen));
I know there is already a lot of topics about simpleXML and PHP, but I need help with an specific xml code.
<vitrine>
<canal>Hotwords</canal>
<product id="0">
<descricao>MP3 Apple iPod Class...</descricao>
<loja>ApetreXo.com</loja>
<preco>à vista R$765,22</preco>
<urlImagem>http://imagem.domain.com.br/thumbs/ensopado/18/80x80_107156_1.jpg</urlImagem>
<urlProduto>http://domain.com.br/tr/rd?o=BiY4C2UnHQ0LOWgyGjc3NRFp-</urlProduto>
</product>
<product id="1">
<descricao>TV Sony Bravia 3D LE...</descricao>
<loja>Fast Shop.com.b...</loja>
<preco>10 x R$299,90</preco>
<urlImagem>http://imagem.domain.com.br/thumbs/ensopado/2852/80x80_319373_1.jpg</urlImagem>
<urlProduto>http://domain.com.br/tr/rd?o=JDEn-</urlProduto>
</product>
</vitrine>
I need a foreach to get the data from each "product" like this:
<?
$feedUrl = 'url to xml file';
$rawFeed = file_get_contents($feedUrl);
$xml = simplexml_load_string($rawFeed);
foreach ($item ...????? ?)
{
}
How can I do this foreach to get the data. I tried all that I know without success.
Thanks.
First, you need <?xml version="1.0" encoding="UTF-8"?> as the first line in your XML, otherwise it's not valid. Then, and this will help you debug all sorts of things over your coding career, try this line:
echo "<pre>".print_r($xml,true)."</pre>";
That will give you the exact layout of the object you get back from the simplexml_load_string() call. From there, since you have a visual of the object layout, you should be able to figure out how to parse it. Incidentally, in your case, I think you'd need to do something like:
foreach($xml->vitrine as $element) {
// your code goes here
}
It seems PHP gets rid of evrything after the whitespace, because product id was changed to just product. Anyway here's the code.
<?php
$v = <<<ABC
<vitrine>
<canal>Hotwords</canal>
<product id="0">
<descricao>MP3 Apple iPod Class...</descricao>
<loja>ApetreXo.com</loja>
<preco>à vista R$765,22</preco>
<urlImagem>http://imagem.domain.com.br/thumbs/ensopado/18/80x80_107156_1.jpg</urlImagem>
<urlProduto>http://domain.com.br/tr/rd?o=BiY4C2UnHQ0LOWgyGjc3NRFp-</urlProduto>
</product>
<product id="1">
<descricao>TV Sony Bravia 3D LE...</descricao>
<loja>Fast Shop.com.b...</loja>
<preco>10 x R$299,90</preco>
<urlImagem>http://imagem.domain.com.br/thumbs/ensopado/2852/80x80_319373_1.jpg</urlImagem>
<urlProduto>http://domain.com.br/tr/rd?o=JDEn-</urlProduto>
</product>
</vitrine>
ABC;
$xml = simplexml_load_string($v);
//print_r($xml);
foreach ($xml->product as $c){
echo $c->loja; //echoing out value of 'loja'
}
Outputs
ApetreXo.com
Fast Shop.com.b...