Page 1 of 1

Array of one element problem

Posted: Sat Apr 17, 2010 10:38 pm
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?

Re: Array of one element problem

Posted: Sat Apr 17, 2010 10:51 pm
by requinix
What are you using to parse the XML? SimpleXML?
What does the XML look like in both cases?

Re: Array of one element problem

Posted: Sat Apr 17, 2010 11:01 pm
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?

Re: Array of one element problem

Posted: Sun Apr 18, 2010 12:07 am
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.

Re: Array of one element problem

Posted: Sun Apr 18, 2010 11:34 am
by JackD
I will edit down the two XML files to include just the applicable XML code. I will then post those for you.

Re: Array of one element problem

Posted: Sun Apr 18, 2010 10:18 pm
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>

Re: Array of one element problem

Posted: Sun Apr 18, 2010 11:39 pm
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 />";
}

Re: Array of one element problem

Posted: Mon Apr 19, 2010 11:00 pm
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.

Re: Array of one element problem

Posted: Tue Apr 20, 2010 12:24 am
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.

Re: Array of one element problem

Posted: Tue Apr 20, 2010 12:56 am
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.

Re: Array of one element problem

Posted: Tue Apr 20, 2010 11:39 am
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