Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does SimpleXML change my array to the array's first element when I use it?

Here is my code:

$string = <<<XML
<?xml version='1.0'?> 
<test>
 <testing>
  <lol>hello</lol>
  <lol>there</lol>
 </testing>
</test>
XML;
$xml = simplexml_load_string($string);
echo "All of the XML:\n";
print_r $xml;
echo "\n\nJust the 'lol' array:";
print_r $xml->testing->lol;

Output:

All of the XML:

SimpleXMLElement Object
(
    [testing] => SimpleXMLElement Object
        (
            [lol] => Array
                (
                    [0] => hello
                    [1] => there
                )

        )

)




Just the 'lol' array:

SimpleXMLElement Object
(
    [0] => hello
)

Why does it output only the [0] instead of the whole array? I dont get it.

like image 869
Qasim Avatar asked Jul 22 '11 22:07

Qasim


3 Answers

What @Yottatron suggested is true, but not at all the cases as this example shows :

if your XML would be like this:

<?xml version='1.0'?>
<testing>
    <lol>
        <lolelem>Lol1</lolelem>
        <lolelem>Lol2</lolelem>
        <notlol>NotLol1</lolelem>
        <notlol>NotLol1</lolelem>
    </lol>
</testing>

Simplexml's output would be:

SimpleXMLElement Object
(
[lol] => SimpleXMLElement Object
    (
        [lolelem] => Array
            (
                [0] => Lol1
                [1] => Lol2
            )

        [notlol] => Array
            (
                [0] => NotLol1
                [1] => NotLol1
            )

    )

)

and by writing

$xml->lol->lolelem

you'd expect your result to be

Array
(
     [0] => Lol1
     [1] => Lol2
)

but instead of it, you would get :

SimpleXMLElement Object 
(
    [0] => Lol1
)

and by

$xml->lol->children()

you would get:

SimpleXMLElement Object
(
[lolelem] => Array
    (
        [0] => Lol1
        [1] => Lol2
    )

[notlol] => Array
    (
        [0] => NotLol1
        [1] => NotLol1
    )

)

What you need to do if you want only the lolelem's:

$xml->xpath("//lol/lolelem")

That gives this result (not as expected shape but contains the right elements)

Array
(
    [0] => SimpleXMLElement Object
    (
        [0] => Lol1
    )

    [1] => SimpleXMLElement Object
    (
        [0] => Lol2
    )

)
like image 193
Taha Paksu Avatar answered Oct 14 '22 01:10

Taha Paksu


what you might want to do is using the Json encode/decode

$jsonArray = Json_decode(Json_encode($xml), true);

With the true argument you can call instead of using -> use [name]

so an example would be:

$xml = file("someXmlFile.xml");
$jsonArray = Json_decode(Json_encode($xml), true);
foreach(jsonArray['title'] as $title){
   Do something with $titles
}

if you have more than 1 element it will typical put in an @attributes if the elements has attributes. This can be countered by using: $title = $title['@attributes']

Hope it could help.

like image 38
Wisienkas Avatar answered Oct 14 '22 02:10

Wisienkas


Ah yes, I remember simple XML nearly doing my head in with this parsing arrays issue Try the below code. It will give you an array of LOL elements, or, if you've just got a single LOL element, it will return that in an array as well.

The main advantage of that is you can do something like foreach ($lol as $element) and it will still work on a single (or on 0) LOL element.

<?php
$string = <<<XML
<?xml version='1.0'?> 
   <test>
     <testing>
      <lol>hello</lol>
      <lol>there</lol>
     </testing>
   </test>
XML;

$xml = simplexml_load_string($string);
echo "<pre>";
echo "All of the XML:\n";
print_r($xml);

echo "\n\nJust the 'lol' array:\n";

$test_lols = $xml->testing->children();              
$childcount = count($test_lols);
if ($childcount < 2) {
    $lol = array($test_lols->lol);                   
}
else {
    $lol = (array) $test_lols;
    $lol = $lol['lol'];
    }

print_r($lol);
?>
like image 43
Silas Palmer Avatar answered Oct 14 '22 00:10

Silas Palmer