【问题标题】:PHP: Return an array from recursive functionPHP:从递归函数返回一个数组
【发布时间】:2019-12-31 07:00:42
【问题描述】:

我有一个这样的数组:

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
                                                                                )

                                                                        )

                                                                )

                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

我需要做的是使用 Anchestors 构建面包屑。列表末尾的应该是第一个。所以,举个例子:

Sport e tempo libero > 类别 > calcio...

我正在尝试以这种方式使用函数迭代 xml,但没有成功:

    $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));

我在 stackoverflow 上发现了类似的东西,但没有任何建议可以帮助我解决这个问题。

【问题讨论】:

  • 我不明白:Fan shop 来自哪里?
  • 我的错误。我编辑了帖子
  • 你能把你的 XML 粘贴到某个地方吗?我想测试我的解决方案以确保它有效。
  • 我在帖子里写的正是我从一个帮助我通过api调用外部服务的类得到的结果
  • 如果您需要复制和粘贴解决方案,请提供 XML。否则,花几分钟时间来理解我的答案,你就会意识到它会起作用。我认为您甚至没有尝试根据您的回答来理解它。

标签: php recursion


【解决方案1】:

要创建具有输出的递归函数,您需要三件事:

  1. 保持当前位置的变量或参数,在您的代码中为$r。 你说对了。
  2. 保存结果的变量或参数,您没有。 起初它似乎是$bread,但它没有任何值,因为每次调用recursive() 时它都是空的。 一个简单的解决方案是在函数内将其声明为global
  3. 检查停止条件的if 语句,您没有。 相反,您的代码中有一个 do-while 循环。

所以,你有两个错误。 根据您的代码并尽可能少地对其进行修改,这是正确的代码:

$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));

你去。

更新:我同意@FlameStorm,如果可能,应该避免使用global。 我还收到了使用static 的建议,但它引入了一个错误。 因此,如果您不确定如何使用它,我建议您也避免使用static

这是改进后的代码:

$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));

不再需要函数外的$bread 变量。 此外,globalstatic 均未使用。

【讨论】:

  • 太棒了!它有效 :) 真的谢谢你,也为了澄清。
【解决方案2】:

SimpleXMLElement 不是数组。您可以将其转换为数组,但 PHP 提供了一个专门针对这种情况的迭代器,SimpleXMLIterator

由于您有一个递归结构,我的建议是使用RecursiveIteratorIterator 将其展平。假设您的数据位于名为 $xml 的变量中,您的解决方案可能如下所示:

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

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

$breadcrumb = array_reverse($breadcrumb);

【讨论】:

  • 阅读我上面的评论,我要求您发布 xml 以便我进行测试。如果没有样本数据,很难提供完美的工作答案!
【解决方案3】:
<?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);

浏览器中的输出:

Sport e tempo libero > 类别 > Calcio > Abbigliamento > Bambine e ragazze
Sport e tempo libero > 类别 > Calcio > Abbigliamento > Bambine e ragazze
(第二行有链接)

生成的html代码:

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>

【讨论】:

    【解决方案4】:

    在上面修复了一个答案 - 如果可以,您应该避免使用 global

    所以,代码将是

    $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);
    

    【讨论】:

      【解决方案5】:

      您也可以使用 $_SESSION 从递归中获取数据

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

      【讨论】:

        猜你喜欢
        • 2013-08-07
        • 2019-01-12
        • 2015-04-27
        • 1970-01-01
        • 2022-01-02
        • 2021-08-14
        • 2011-03-29
        • 1970-01-01
        • 2016-01-24
        相关资源
        最近更新 更多