Why does SimpleXML change my array to the array

2019-02-13 06:25发布

问题:

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.

回答1:

It's because you have two lol elements. In order to access the second you need to do this:

$xml->testing->lol[1];

this will give you "there"

$xml->testing->lol[0];

Will give you "hello"

The children() method of the SimpleXMLElement will give you an object containing all the children of an element for example:

$xml->testing->children();

will give you an object containing all the children of the "testing" SimpleXMLElement.

If you need to iterate, you can use the following code:

foreach($xml->testing->children() as $ele)
{
    var_dump($ele);
}

There is more information about SimpleXMLElement here:

http://www.php.net/manual/en/class.simplexmlelement.php



回答2:

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
    )

)


回答3:

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.



回答4:

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);
?>


回答5:

Ran into this issue...

Xpath can be a little slow, so you can achieve the same effect with a simple for loop.

for ($i = 0; $i < count($xml->testing->lol); $i++) {
    print_r($xml->testing->lol[$i]);
}