Array of one element problem

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
JackD
Forum Commoner
Posts: 62
Joined: Sat Dec 12, 2009 6:25 pm

Array of one element problem

Post by JackD »

Code: Select all

$parsed_xml = simplexml_load_string($Response); 
$Items = (array)$parsed_xml->Items; 
$Item = (array)$Items['Item'];     // up to 10 max
if ($Item[0])
     foreach ($Item as $i=>$Item_Data)
         print_product($i, $Item_Data); 
   else print_product(-1, $Item);           
In the above code, as long as there are 2 or more elements in $Item, everything is fine. If there is only a single item, a different structure is returned and $Item[0] is null. The above code detects the single element array, but the structure must be accessed differently. For example, for a multiple element array,

Code: Select all

$EAN = $Item_Data->ItemAttributes->EAN;
will return the proper value, but with a single element array the field must be accessed with

Code: Select all

$EAN = $Item[ItemAttributes]->EAN
.

Is there a way to fix this so the same code can be used with single or multiple element arrays?
Last edited by JackD on Sat Apr 17, 2010 10:57 pm, edited 1 time in total.
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: Array of one element problem

Post by requinix »

What are you using to parse the XML? SimpleXML?
What does the XML look like in both cases?
JackD
Forum Commoner
Posts: 62
Joined: Sat Dec 12, 2009 6:25 pm

Re: Array of one element problem

Post by JackD »

Code: Select all

$parsed_xml = simplexml_load_string($Response); 
is what is being used to parse the xml. The XML for a single item is quite large, and grows with each additional item. What is the best way to get them where you can see them?
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: Array of one element problem

Post by requinix »

As long as the <Item> node has some number of <ItemAttributes> children, be that one or many, you should be able to just iterate over it.

Code: Select all

foreach ($Item_Data->ItemAttributes->EAN as $ean) {
It would really help to see the XML, even if just an example of the stuff around the <Item> nodes.
JackD
Forum Commoner
Posts: 62
Joined: Sat Dec 12, 2009 6:25 pm

Re: Array of one element problem

Post by JackD »

I will edit down the two XML files to include just the applicable XML code. I will then post those for you.
JackD
Forum Commoner
Posts: 62
Joined: Sat Dec 12, 2009 6:25 pm

Re: Array of one element problem

Post by JackD »

Here is a complete failing program:

Code: Select all

<?php require_once('getrequest.php'); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<?php 
$XML1='<?xml version="1.0" ?><ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2009-02-01"><Items><Item><ASIN>045122499X</ASIN><ItemAttributes><Author>Ken Follett</Author><EAN>9780451224996</EAN></ItemAttributes></Item><Item><ASIN>0525951652</ASIN><ItemAttributes><Author>Ken Follett</Author><EAN>9780525951650</EAN></ItemAttributes></Item><Item><ASIN>0330509918</ASIN><ItemAttributes><Author>Ken Follett</Author><EAN>9780330509916</EAN></ItemAttributes></Item><Item><ASIN>033050990X</ASIN><ItemAttributes><Author>Ken Follett</Author><EAN>9780330509909</EAN></ItemAttributes></Item><Item><ASIN>006136472X</ASIN><ItemAttributes><Author>Ken Follett</Author><EAN>9780061364723</EAN></ItemAttributes></Item><Item><ASIN>0330345044</ASIN><ItemAttributes><Author>Ken Follett</Author><EAN>9780330345040</EAN></ItemAttributes></Item></Items></ItemSearchResponse>';

$XML2='<?xml version="1.0" ?><ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2009-02-01"><Items><Item><ASIN>006136472X</ASIN><ItemAttributes><Author>Ken Follett</Author><EAN>9780061364723</EAN></ItemAttributes></Item></Items></ItemSearchResponse>';

function Display_Items($XML_String)
{ $parsed_xml = simplexml_load_string($XML_String); 
  $Items = (array)$parsed_xml->Items; 
  $Item = (array)$Items['Item'];     // up to 10 max
  if ($Item[0])
     foreach ($Item as $i=>$Item_Data)
         echo 'Multiple Items# ' . $i . ' : ' . $Item_Data->ItemAttributes->EAN . '<br>'; 
   else 
     { echo 'Single Item: ' . $Item[ItemAttributes]->EAN . '<br>';
       foreach ($Item as $i=>$Item_Data)
         echo 'Failing Item# ' . $i . ' : ' . $Item_Data->EAN . '<br>';
     }          
}

Display_Items($XML1);
Display_Items($XML2);
?>
</body>
</html>
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: Array of one element problem

Post by Benjamin »

The code you posted above is a perfect example of why braces should always be used. Other than the indentation, I had no other indicators to tell me what was apart of the if and foreach statement. Anyhow, this code will parse the XML feed correctly.

Code: Select all

<?php
try {
    $xml = new SimpleXmlElement($foo);

    foreach ($xml->Items->Item as $Item) {
        echo "ASIN: " . iconv("UTF-8", "CP1252", $Item->ASIN) . "<br />";
        echo "Author: " . iconv("UTF-8", "CP1252", $Item->ItemAttributes->Author) . "<br />";
        echo "EAN: " . iconv("UTF-8", "CP1252", $Item->ItemAttributes->EAN) . "<br />";
        echo "<br />";
    }
} catch (Exception $e) {
    echo "PARSE ERROR: {$e->getMessage()}<br />";
}
JackD
Forum Commoner
Posts: 62
Joined: Sat Dec 12, 2009 6:25 pm

Re: Array of one element problem

Post by JackD »

I tried adding the braces and it made no difference whatsoever. The braces, or lack thereof, had no bearing on the problem.

You did provide a solution that side-stepped the problem. By doing away with the lines:

Code: Select all

$Items = (array)$parsed_xml->Items; 
$Item = (array)$Items['Item'];
and replacing

Code: Select all

foreach ($Items->Item as $i=>$Item_Data)
with

Code: Select all

foreach ($parsed_xml->Items->Item as $i=>$Item_Data)
While this does side-step the problem, and I thank you for that because it gives me a work-around for this particular case, the original problem still exists. If you examine the value of $parsed_xml for each of the two XML strings you will find XML1 breaks into 6 "elements" of data that can be referenced as "element[0]", "element[1]", etc. while the value of $parsed_xml for XML2 does not provide an "element[0]" as it should.

The point is that the data "elements" should always be represented in the same manner whether there is only a single element or multiple elements.
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: Array of one element problem

Post by Benjamin »

JackD wrote:I tried adding the braces and it made no difference whatsoever. The braces, or lack thereof, had no bearing on the problem.
Right. Although the code was syntactically correct, the issue here was readability and maintainability. Please don't take it personally, I was merely pointing out that this was an example of why braces should be used.

Code: Select all

$Items = (array)$parsed_xml->Items;
Is correct. This contains one or more Items.

Code: Select all

$Item = (array)$Items['Item'];
Is not correct because there can be more than one item. Which item are you trying to return?

Code: Select all

$Item = (array)$Items[$key];
Is how to properly access a specific item.

The solution I provided iterates through each item and is correct. The number of items is not relevant.

I am confused when you say that this side-steps the problem. I don't feel that a valid solution, which indeed fixes a problem and works correctly is a side-step or band aid.
User avatar
Eran
DevNet Master
Posts: 3549
Joined: Fri Jan 18, 2008 12:36 am
Location: Israel, ME

Re: Array of one element problem

Post by Eran »

If you examine the value of $parsed_xml for each of the two XML strings you will find XML1 breaks into 6 "elements" of data that can be referenced as "element[0]", "element[1]", etc. while the value of $parsed_xml for XML2 does not provide an "element[0]" as it should.

The point is that the data "elements" should always be represented in the same manner whether there is only a single element or multiple elements.
You misinterpret how SimpleXML treats single items in this case - "element" would not be an array but simply the item. SimpleXML objects are not arrays, they merely implement some array like behavior. If you access a property directly it could either be an array or a single item, depending on the data in the XML. Using a foreach loop however will work regardless if it's a single item or multiple item - and this is why Benjamin's solution is correct and not a sidestep.
JackD
Forum Commoner
Posts: 62
Joined: Sat Dec 12, 2009 6:25 pm

Re: Array of one element problem

Post by JackD »

Thanks, Pytrin. Knowing that SimpleXML treats single element XML differently than multiiple element XML answers my question. I could tell that a single element was being returned differently than multiple items, and that was what was creating the confusion on my part, because I thought perhaps I was causing the problem.

I wanted something that would return the same structure regardless of the number of elements so I could reference them as element[0], element[1], etc. in all cases rather than continually having to check to see if I had only a single element or multiple elements. I need to reference the elements individually by index value rather than always doing a foreach and counting down to the one I need. So, I will have to do a foreach at first to build an array of elements I can use later in the code.

Thanks
Post Reply