11

I have an array like this one:

SimpleXMLElement Object
(
    [BrowseNodes] => SimpleXMLElement Object
        (
            [BrowseNode] => SimpleXMLElement Object
                (
                    [BrowseNodeId] => 969391031
                    [Name] => Bambine e ragazze
                    [Children] => SimpleXMLElement Object
                        (
                            [BrowseNode] => Array
                                (
                                    [0] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 969394031
                                            [Name] => Calze
                                        )

                                    [1] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635837031
                                            [Name] => Felpe
                                        )

                                    [2] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635838031
                                            [Name] => Giacche
                                        )

                                    [3] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635839031
                                            [Name] => Guanti da giocatore
                                        )

                                    [4] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 969392031
                                            [Name] => Maglie
                                        )

                                    [5] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 4351854031
                                            [Name] => Maglie per tifosi
                                        )

                                    [6] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635840031
                                            [Name] => Magliette da portiere
                                        )

                                    [7] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 969393031
                                            [Name] => Pantaloncini
                                        )

                                    [8] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635841031
                                            [Name] => Pantaloncini da portiere
                                        )

                                    [9] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635842031
                                            [Name] => Pantaloni
                                        )

                                    [10] => SimpleXMLElement Object
                                        (
                                            [BrowseNodeId] => 3635843031
                                            [Name] => Tute da ginnastica
                                        )

                                )

                        )

                    [Ancestors] => SimpleXMLElement Object
                        (
                            [BrowseNode] => SimpleXMLElement Object
                                (
                                    [BrowseNodeId] => 969386031
                                    [Name] => Abbigliamento
                                    [Ancestors] => SimpleXMLElement Object
                                        (
                                            [BrowseNode] => SimpleXMLElement Object
                                                (
                                                    [BrowseNodeId] => 937258031
                                                    [Name] => Calcio
                                                    [Ancestors] => SimpleXMLElement Object
                                                        (
                                                            [BrowseNode] => SimpleXMLElement Object
                                                                (
                                                                    [BrowseNodeId] => 524013031
                                                                    [Name] => Categorie
                                                                    [IsCategoryRoot] => 1
                                                                    [Ancestors] => SimpleXMLElement Object
                                                                        (
                                                                            [BrowseNode] => SimpleXMLElement Object
                                                                                (
                                                                                    [BrowseNodeId] => 524012031
                                                                                    [Name] => Sport e tempo libero
                                                                                )

                                                                        )

                                                                )

                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

What I need to do is to build a breadcrumb using Anchestors. The one that is at the end of the list should be the first one. So, as an example:

Sport e tempo libero > Categorie > calcio...

I'm trying to iterate the xml with a function in this way without success:

    $rec=$result->BrowseNodes->BrowseNode->Ancestors->BrowseNode;

    $bread=array();
    function recursive($r)
    {
        do{
            $bread[]=$r->BrowseNodeId;
            recursive($r->Ancestors->BrowseNode);
        }while(isset($r->Ancestors));
        $bread=array_reverse($bread);
        return $bread;
    }

    print_r(recursive($rec));

I found something similar on stackoverflow but no suggestions helped me to sort this out.

5
  • I don't understand: where does Fan shop come from? Commented Dec 9, 2016 at 17:38
  • my mistake. I edited the post Commented Dec 9, 2016 at 17:40
  • Can you paste your XML somewhere? I'd like to test my solution to make sure it works. Commented Dec 11, 2016 at 22:55
  • What I wrote inside the post is exactly the result I receive from a class that help me to call an external service through api Commented Dec 12, 2016 at 0:04
  • 3
    Please provide the XML if you want a copy and paste solution. Otherwise, take a few minutes to comprehend my answer and you'll realize it will work. I don't think you even tried to understand it based on your response. Commented Dec 12, 2016 at 0:39

5 Answers 5

11
+50

To create a recursive function with an output, you need three things:

  1. A variable or a parameter to hold the current position, which is $r in your code. You got this one right.
  2. A variable or a parameter that holds the result, which you don't have. At first it appears to be $bread, but it is not holding any value because it is empty every time you call recursive(). A simple solution is to declare it as global inside the function.
  3. An if statement that checks the stop condition, which you don't have. Instead, you have a do-while loop in your code.

So, you have two mistakes there. Based on your code and modifying it as little as possible, this is the correct code:

$rec = $result->BrowseNodes->BrowseNode->Ancestors->BrowseNode;

$bread = array();
function recursive($r)
{
    global $bread;

    $bread[] = strval($r->BrowseNodeId);

    if(isset($r->Ancestors)){
        return recursive($r->Ancestors->BrowseNode);
    }else{
        return array_reverse($bread);
    }
}

print_r(recursive($rec));

There you go.

Update: I agree with @FlameStorm, global should be avoided if possible. I also received suggestion to use static instead, but it introduces a bug. Thus, I recommend avoiding static as well if you're not sure how to use it.

This is the improved code:

$rec = $result->BrowseNodes->BrowseNode->Ancestors->BrowseNode;

function recursive($r)
{
    if(isset($r->Ancestors))
        $bread = recursive($r->Ancestors->BrowseNode);

    $bread[] = strval($r->BrowseNodeId);
    return $bread;
}

print_r(recursive($rec));

The $bread variable outside the function is no longer needed. Also, neither global or static is used.

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

1 Comment

Great! it works :) Thank you really, also for clarification.
4

SimpleXMLElement is not an array. You could convert it to an array, but PHP offers an iterator specifically for this case, SimpleXMLIterator.

Since you have a recursive structure, my suggestion is to flatten it with RecursiveIteratorIterator. Assuming your data is in a variable called $xml, your solution might look something like this:

$xmlIterator  = new SimpleXMLIterator($xml->Ancestors);
$flatIterator = new RecursiveIteratorIterator($xmlIterator, RecursiveIteratorIterator::SELF_FIRST);

$breadcrumb = [];
foreach($flatIterator as $node) {
    $breadcrumb[] = $node['Name'];
}

$breadcrumb = array_reverse($breadcrumb);

1 Comment

Read my comment above, I asked for you to post the xml so I could test. Pretty hard to deliver a perfect working answer without the sample data!
0
<?php
$sxe = new SimpleXMLElement("BrowseNodes.xml", NULL, TRUE);

// prepare a String for the SimpleXMLIterator.
// The SimpleXMLIterator expects:
// "A well-formed XML string or the path or URL to an XML document"
// therefore get the xml-string by calling asXML() on the 
$partitialXMLString = $sxe->BrowseNodes->BrowseNode->Ancestors->asXML();

$recursiveIterator = new RecursiveIteratorIterator(
        new SimpleXMLIterator($partitialXMLString), 
        RecursiveIteratorIterator::CHILD_FIRST
);

// if you need only the names
$name = array();

// if you need the links to something
$link = array();
$baseUrl = "http://example.com/BrowseNodeId/";

// if you need just the nodes in an array, and create the output later from it
// $xmlNode = array()

foreach($recursiveIterator as $node) {
    if (false == empty($node->Name)){
        $name[] = (string) $node->Name;
        $link[] = "<a href='" . $baseUrl . $node->BrowseNodeId . "'>" .  $node->Name . "</a>\n";

        // for later processing
        // $xmlNode[] = $node; 
    }
}

// Add the top BrowseNode->Name, from the node, where the First "Ancestors" is.
// This could be done also in the loop, when looping over all elements, 
// by adding conditions in order to differentiate between Children and Ancestors
// But this is more readable, and for your structure should be enough.
$firstNode = $sxe->BrowseNodes->BrowseNode;
$name[] = $firstNode->Name;
$link[] = "<a href='" . $baseUrl . $firstNode->BrowseNodeId . "'>" .  $firstNode->Name . "</a>\n";
// $xmlNode[] = $firstNode;

//output the path (child first)
// &gt; is  >
echo implode(' &gt; ', $name); 

echo "<br>\n";
//output the links (child first)
echo implode(' &gt; ', $link);

The output in browser:

Sport e tempo libero > Categorie > Calcio > Abbigliamento > Bambine e ragazze
Sport e tempo libero > Categorie > Calcio > Abbigliamento > Bambine e ragazze
( the second line with links)

The generated html code:

Sport e tempo libero &gt; Categorie &gt; Calcio &gt; Abbigliamento &gt; Bambine e ragazze<br>
<a href='http://example.com/BrowseNodeId/524012031'>Sport e tempo libero</a>
 &gt; <a href='http://example.com/BrowseNodeId/524013031'>Categorie</a>
 &gt; <a href='http://example.com/BrowseNodeId/937258031'>Calcio</a>
 &gt; <a href='http://example.com/BrowseNodeId/969386031'>Abbigliamento</a>
 &gt; <a href='http://example.com/BrowseNodeId/969391031'>Bambine e ragazze</a>

Comments

0

Fixed one answer above - you should avoid global if you can.

So, the code will be

$rec = $result->BrowseNodes->BrowseNode->Ancestors->BrowseNode;

function recursive($r)
{
    $breads = [strval($r->BrowseNodeId)];

    if (isset($r->Ancestors)) {
        $breads = array_merge(recursive($r->Ancestors->BrowseNode), $breads);
    }

    return $breads;
}

$breadcrumbs = recursive($rec); // You got it.
print_r($breadcrumbs);

Comments

-2

Alternatively you can use $_SESSION for getting data from recursion

function start(){
$_SESSION['new1']=[];
$this->recursive($array);
$newVal = $_SESSION['new1'];
$_SESSION['new1']=[];
return $newVal;
}

function recursive($array){
...
$_SESSION['new1'][] = $val;
...
}

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.