0

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!

1
  • 2
    $data is not an array, it's an instance of SimpleXMLElement, use it accordingly: $data->merchant->prod[0]; Commented Mar 10, 2015 at 13:36

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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'])

4 Comments

I think this way, as it's more like the arrays I'm used to. How would I access the value 690579815?
That's why I proposed it. Access that value by $data['merchant']['prod'][0]['id]
@lee, you can't using this method, but you can using the data as a SimpleXMLElement see this answer on how to access node attributes
Thanks Elias! I used the following and it worked: $data->merchant->prod[0]->attributes()->id
0

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

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.