7

I think I'm missing something really obvious here, but can someone explain to me why I'm getting the output I am and not the output I expect on the following var dumps:

Here's the original xml:

<result>
    <category>
        <id>3</id>
        <name>Category 1</name>
        <subcategory>
            <id>9</id>
            <name>SubCat 1</name>
        </subcategory>
        <subcategory>
            <id>10</id>
            <name>SubCat 2</name>
        </subcategory>
        <subcategory>
            <id>11</id>
            <name>SubCat 3</name>
        </subcategory>
    </category>
</result>

What I am doing:

$xml = new SimpleXMLElement($file);
foreach($xml->category as $node)
{
    echo "dump 1:
";
    var_dump($node);
    echo "**********************************************
dump 2:
";
    var_dump($node->subcategory);
    die();
}

This outputs:

dump 1:
object(SimpleXMLElement)#130 (3) {
    ["id"]=>
    string(1) "3"
    ["name"]=>
    string(10) "Category 1"
    ["subcategory"]=>
    array(3) {
        [0]=>
        object(SimpleXMLElement)#133 (2) {
            ["id"]=>
            string(1) "9"
            ["name"]=>
            string(8) "SubCat 1"
        }
        [1]=>
        object(SimpleXMLElement)#135 (2) {
            ["id"]=>
            string(2) "10"
            ["name"]=>
            string(8) "SubCat 2"
        }
        [2]=>
        object(SimpleXMLElement)#136 (2) {
            ["id"]=>
            string(2) "11"
            ["name"]=>
            string(8) "SubCat 3"
        }
    }
}
**********************************************
dump 2:
object(SimpleXMLElement)#138 (2) {
    ["id"]=>
    string(1) "9"
    ["name"]=>
    string(8) "SubCat 1"
}

The first var dump outputs what I'd expect, but the output I would expect for the second var_dump would be:

array(3) {
    [0]=>
    object(SimpleXMLElement)#133 (2) {
        ["id"]=>
        string(1) "9"
        ["name"]=>
        string(8) "SubCat 1"
    }
    [1]=>
    object(SimpleXMLElement)#135 (2) {
        ["id"]=>
        string(2) "10"
        ["name"]=>
        string(8) "SubCat 2"
    }
    [2]=>
    object(SimpleXMLElement)#136 (2) {
        ["id"]=>
        string(2) "11"
        ["name"]=>
        string(8) "SubCat 3"
    }
}

Or even an object containing all the array items. Why is this not the case?

I can see when I call var_dump($node->subcategory) it's dumping the first 'subcategory' node that it finds, but why then does it cast all the 'subcategory' nodes to an array for the first var dump but not for the second? And how would I mimic this behaviour to detect if 'subcategory' contains more than one object (as it does in the first var dump)?

Basically what I'm trying to do is detect if a property of the SimpleXMLElement contains an array of more values (i.e. if it contains child nodes)

I've tried all sorts, but I can't seem to detect if one of the properties of the simpleXml object contains a set of arrays.

Update:

I found this works:

if(count($node->subcategory)>1)
{
    // we have  more than one subcategory
}

But it's not the most elegant way, I'm sure there must be a cleaner method?

hakre
  • 193,403
  • 52
  • 435
  • 836
Stu
  • 4,160
  • 24
  • 43
  • the answer to this post might help you: http://stackoverflow.com/questions/2751711/php-get-values-from-simplexmlelement-array?rq=1 **var_dump($node["subcategoy"]);** – feskr Oct 03 '12 at 14:32
  • @feskr thanks, I'm pushing all the properties (and therefore attributes) through a foreach loop in my actual code and it doesn't seem to differentiate between attributes and properties, which is a problem! – Stu Oct 03 '12 at 14:43
  • @feskr `var_dump($node["subcategory"])` outputs: `NULL` – Stu Oct 03 '12 at 14:51
  • i'm sorry, i have another for you in answer – feskr Oct 03 '12 at 15:14

4 Answers4

3

This property is object of iterarator:

$node->subcategory

And if you need to get all items try:

foreach($xml->category as $node)
{
...
  foreach($node->subcategory as $subcategory)
  {
     $data[] = (array) $subcategory
  }
...
}

If you need to know count of subcategory items you successfully used count-method.

And you may use xpath if will not change XML tree:

$categories = $xml->xpath('/category/subcategory');
var_dump($categories)
Yegor Lukash
  • 510
  • 2
  • 18
  • the xpath method won't work in my particular scenario as subcategories can be recursive (nightmare!). However, the $data method is nicely adaptable, thanks! – Stu Oct 03 '12 at 15:49
1

Adjust your xml file:

<result>
    <category>
        <id>3</id>
        <name>Category 1</name>
        <subcategories>
          <subcategory>
            <id>9</id>
            <name>SubCat 1</name>
          </subcategory>
          <subcategory>
            <id>10</id>
            <name>SubCat 2</name>
          </subcategory>
          <subcategory>
            <id>11</id>
            <name>SubCat 3</name>
          </subcategory>
        </subcategories>
    </category>
</result>

And try:

var_dump($node->subcategories);
feskr
  • 759
  • 6
  • 10
0

I think that the main point was indicated by Yegor Lukash, saying that it's an Iterator.

However, you can get the expected result this way:

foreach($xml->category as $node)
{
    $subcategories = ((array)$node)['subcategory'];   
    var_dump($subcategories);
}

About the feskr answer, I think it can be useful to obtain a clearer xml code, and in such case my solution would become:

foreach($xml->category as $node)
{
    $subcategories = ((array)$node->subcategories)['subcategory'];
    var_dump($subcategories);
}

But in that case it would be better this:

foreach($xml->category as $node)
{
    foreach($node->subcategories->children() as $subcategory) {
      var_dump($subcategory);
    }
}
Tama
  • 181
  • 1
  • 6
0

( since this XML thingy caused tons of trouble for me , i switched to the "give me an associative array" by using

$myarray = json_decode(json_encode(simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

That way the "CDATA[" parts are also included as clear text

regards

Bencho Naut
  • 348
  • 1
  • 6