Lee
Lee

Reputation: 1495

PHP access array within XML

I have a PHP script that loads an XML sheet like so:

$feed = 'mydata.xml';
$xml = file_get_contents($feed);
$data = simplexml_load_string($xml);

echo print_r($data);

The result looks like this (although I've chopped a lot out):

SimpleXMLElement Object
(
    [merchant] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [id] => 1
                    [name] => companyname
                )

            [prod] => Array
                (
                    [0] => SimpleXMLElement Object
                         (
                            [@attributes] => Array
                                (
                                     [id] => 690579815
                                     [lang] => en
                                     [pre_order] => no
                                     [web_offer] => yes
                                     [in_stock] => yes
                                )

My question is, how can I access the prod array? I want to be able to count it like so:

count($data['prod']);

And also get particular field values but I'm quite new to PHP and XML and can't quite do it.

Thanks!

Upvotes: 0

Views: 765

Answers (3)

hakre
hakre

Reputation: 198217

My question is, how can I access the prod array?

You can't. Because there is no array. But it's okay you ask, it's just print_r has been fooling you a little. SimpleXMLElement is an object and it can change what will be shown when it gets print_r'ed and it fakes you some arrays there.

Some basics to the rescue:

$data represents the document element of the XML you have. In case you're in doubt what's in the XML, instead of print_r look into $data->asXML() (if you look through your browser view source or hint the output as plain-text otherwise the browser will hide all tags).

$data['prod'] gives you the attribute named prod on that document element. As there is none, it returns null:

var_dump($data['prod']);   ---   NULL

And the count of NULL is 0:

var_dump(count(NULL));     ---   int(0)

You neither want to look into the document element nor do you want to look-up attributes. You're interested in the child-elements named prod inside the merchant element.

So first obtain the first merchant element:

$merchant = $data->merchant;

You obtain elements with object access, that is with the object operator ->.

And the get the count of the number of child elements named prod:

var_dump(count($merchant->prod));   ---   int(3)

As this shows, I've got three (3) children named prod inside the merchant element represented by $merchant.

So you don't need any array here, the SimpleXMLElement allows you access to all the XML-elements inside the XML document.

As written earlier, the array brackets are used for array-access. So it looks like an array, but it is actually an object. It has been used to access the attributes. But this is only true, if the key is not a number. If it's a number, it will access the n-th named element:

var_dump($merchant->prod[0]->asXML());

Will give the XML of the first prod element of the merchant element:

string(94) "<prod id="690579815" lang="en" pre_order="no" web_offer="yes" in_stock="yes">product #1</prod>"

As it is the first element, you can obtain it's id attribute as well:

var_dump($merchant->prod[0]['id']->asXML());

Which returns exactly that attribute:

string(15) " id="690579815""

But it does not stop here. Each of these SimpleXMLElement objects of XML elements and attributes can be cased to string:

var_dump((string)$merchant->prod[0]);         ---   string(10) "product #1"
var_dump((string)$merchant->prod[0]['id']);   ---   string(9) "690579815"

Which is most often the actual information you're looking for. When you use echo or similar, this string-casting is done automatically btw.

echo $merchant->prod[0]; // prints: "product #1"

Similar to arrays (and object), you can also iterate over each SimpleXMLElement. For example the $merchant element:

foreach ($merchant as $children)
{
    echo $children->asXML(), "\n";
}

Gives:

<merchant id="1" name="companyname">
        <prod id="690579815" lang="en" pre_order="no" web_offer="yes" in_stock="yes">product #1</prod>
        <prod id="250544605" lang="en" pre_order="no" web_offer="yes" in_stock="yes">product #2</prod>
        <prod id="360355798" lang="en" pre_order="no" web_offer="yes" in_stock="yes">product #3</prod>
</merchant>

Which is a single element. So more interesting this is with named child-elements:

foreach ($merchant->prod as $prod)
{
    echo $prod->asXML(), "\n";
}

This now gives all children named prod one after the other:

<prod id="690579815" lang="en" pre_order="no" web_offer="yes" in_stock="yes">product #1</prod>
<prod id="250544605" lang="en" pre_order="no" web_offer="yes" in_stock="yes">product #2</prod>
<prod id="360355798" lang="en" pre_order="no" web_offer="yes" in_stock="yes">product #3</prod>

You find this as well explained in Basic SimpleXML usage in the PHP manual. Consult it as another source.

Just take these rules:

  • print_r and var_dump cheat on you when used with SimpleXMLElement
  • You don't need an array when you've got a SimpleXMLElement already
  • In case SimpleXMLElement is too simple in data-access, it's sister DOM library can be used easily as you can switch over to it.

See the full example.

Upvotes: 1

Bas van Dorst
Bas van Dorst

Reputation: 6640

SimpleXMLElement is an object, so you also need to access them as an object:

print count($data->merchant->prod);

Upvotes: 0

n-dru
n-dru

Reputation: 9440

To access it as associative array, do this:

$data = json_decode(json_encode($data), true);

then you can access it like this:

count($data['merchant']['prod'])

Upvotes: 0

Related Questions