Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extracting data form XML file with SimpleXML in PHP

Tags:

php

simplexml

Introduction:

I want to loop through XML files with flexible categories structure.

Problem:

I don't know to loop through a theoretical infinte subcategories without having to make x amount of "for each" statements (See coding example in the bottom). How do I dynamically traverse the categories structure?

<?xml version="1.0" encoding="utf-8"?>
<catalog>
    <category name="Category - level 1">
        <category name="Category - level 2" />
        <category name="Category - level 2">
            <category name="Category - level 3" />
        </category>
        <category name="Category - level 2">
            <category name="Category - level 3">
                <category name="Category - level 4" />
            </category>
        </category>
    </category>
</catalog>

What I have now:

I have no problem looping through XML files with a set structure:

<catalog>
    <category name="Category - level 1">
        <category name="Category - level 2">
            <category name="Category - level 3" />
        </category>
        <category name="Category - level 2">
            <category name="Category - level 3" />
        </category>
    </category>
</catalog>

Coding example:

//$xml holds the XML file
foreach ( $xml AS $category_level1 )
{
    echo $category_level1['name'];

    foreach ( $category_level1->category AS $category_level2 )
    {
        echo $category_level2['name'];

        foreach ( $category_level2->category AS $category_level3 )
        {
           echo $category_level3['name'];
        }
    }
}
like image 525
Cudos Avatar asked Dec 29 '22 21:12

Cudos


1 Answers

Getting the name attributes from your categories is likely fastest when done via XPath, e.g.

$categoryNames = $doc->xpath('//category/@name');

However, if you want to recursively iterate over an arbitrary nested XML structure, you can also use the SimpleXMLIterator, e.g. with $xml being the string you gave:

$sxi = new RecursiveIteratorIterator(
           new SimpleXMLIterator($xml), 
           RecursiveIteratorIterator::SELF_FIRST);

foreach($sxi as $node) {
    echo str_repeat("\t", $sxi->getDepth()), // indenting
         $node['name'],                      // getting attribute name
         PHP_EOL;                            // line break
}

will give

Category - level 1
    Category - level 2
    Category - level 2
        Category - level 3
    Category - level 2
        Category - level 3
            Category - level 4

Like said in the beginning, when just wanting to get all name attributes, use XPath, because iterating over each and every node is slow. Use this approach only when you want to do more complex things with the nodes, for instance adding something to them.

like image 150
Gordon Avatar answered Dec 31 '22 11:12

Gordon