user3783243
user3783243

Reputation: 5224

SimpleXMLElement foreach child Array/Value

I have the following code which works but seems like the incorrect way to implement this. Disregard the "...." that is all extra stuff we need not be concerned by. The issue I was having was that Sup was an array some of the time and other times it was just a value (or so print_r claimed, I thought/hoped it would have just been a one element array).

$users is a simpleXMLElement.

foreach($users as $user) {
    if ($user->InstSup->Sup[1] == '') {
        foreach($user->InstSup as $affid) {
        ....
    } else {
        foreach($user->InstSup->Sup as $affid) {

Here are the varying instances...

<Users>
    <User>
        <InstSup><Sup>1</Sup></InstSup>
    </User>
    <User>
        <InstSup><Sup>2</Sup><Sup>3</Sup><Sup>4</Sup><Sup>5</Sup></InstSup>
    </User>
</Users>

Thanks.

Upvotes: 0

Views: 114

Answers (1)

hakre
hakre

Reputation: 197732

First of all, don't trust the output of print_r (or var_dump) when you deal with SimpleXMLElements. It's not showing the whole picture, better take a look at the XML as-is, for example with the asXML() method.

Now to the problem you've got. When you want to have just the list (so to speak an "array") of the <Sup> elements that are children of <InstSup>, you better query the document with Xpath. It's fairly straight forward and gives you the array you want:

$users = new SimpleXMLElement($buffer);
$sups  = $users->xpath('/Users/User/InstSup/Sup');
foreach ($sups as $index => $sup) {
    printf("#%d: %s (%s)\n", $index, $sup, $sup->asXML());
}

This creates the following output:

#0: 1 (<Sup>1</Sup>)
#1: 2 (<Sup>2</Sup>)
#2: 3 (<Sup>3</Sup>)
#3: 4 (<Sup>4</Sup>)
#4: 5 (<Sup>5</Sup>)

And this is the $buffer to complete the example:

$buffer = <<<XML
<Users>
    <User>
        <InstSup><Sup>1</Sup></InstSup>
    </User>
    <User>
        <InstSup><Sup>2</Sup><Sup>3</Sup><Sup>4</Sup><Sup>5</Sup></InstSup>
    </User>
</Users>
XML;

As the line-up in the output shows, even though the <Sup> elements are inside (same-named but) different parent elements, the XPath query expression

/Users/User/InstSup/Sup

returns all the elements in that path from the document.

So hopefully you now better understand that it's not only that print_r is not that useful because it doesn't show the whole picture, but also by understanding how the document has it's nodes ordered, you can even more easily query the data with an Xpath expression.

Upvotes: 1

Related Questions