2016-12-09 14 views
8

Mam tablicę jak ten:PHP: Zwraca tablicę z funkcji rekurencyjnej

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 
                       ) 

                     ) 

                   ) 

                 ) 

               ) 

             ) 

           ) 

         ) 

       ) 

     ) 

) 

Co muszę zrobić, to zbudować nawigacyjnego korzystając Anchestors. Ten, który znajduje się na końcu listy, powinien być pierwszy. Tak więc, jako przykład:

Sport e tempo libero> Kategoria> calcio ...

Próbuję iteracyjne XML z funkcji w ten sposób bez powodzenia:

$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 znalazłem coś podobnego na stackoverflow, ale żadne sugestie nie pomogły mi rozwiązać tego problemu.

+0

nie rozumiem: skąd 'Fan shop' pochodzi? – cFreed

+0

mój błąd. Edytowałem posta – Luca

+0

Czy możesz wkleić gdzieś swój kod XML? Chciałbym przetestować moje rozwiązanie, aby upewnić się, że działa. – quickshiftin

Odpowiedz

9

celu utworzenia funkcji rekurencyjnej z wyjściem, potrzebne są trzy rzeczy:

  1. zmiennej lub parametru posiadać aktualną pozycję, która jest $r w twoim kodzie. Masz to prawo.
  2. Zmienna lub parametr zawierający wynik, którego nie masz. Na początku wygląda na to, że jest $bread, ale nie zawiera żadnej wartości, ponieważ jest pusta przy każdym wywołaniu recursive(). Prostym rozwiązaniem jest zadeklarowanie go jako global wewnątrz funkcji.
  3. Instrukcja if, która sprawdza warunek zatrzymania, którego nie masz. Zamiast tego w kodzie znajduje się pętla do-while.

Masz dwa błędy. podstawie kodu i modyfikując go w jak najmniejszym stopniu, to jest poprawny kod:

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

tam udać.

Aktualizacja: Zgadzam się z @FlameStorm, global należy unikać, jeśli to możliwe. Otrzymałem również propozycję użycia static zamiast tego, ale wprowadza błąd. Dlatego też, jeśli nie jesteś pewien, jak go używać, radzę unikać również static.

Jest to ulepszona Kod:

$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 zmienna poza funkcją nie jest już potrzebna. Nie jest również używane global ani static.

+0

Świetnie! to działa :) Dziękuję bardzo, także za wyjaśnienie. – Luca

4

SimpleXMLElement nie jest tablicą. Można go przekonwertować do tablicy, ale PHP oferuje iterator specjalnie dla tego przypadku, SimpleXMLIterator.

Ponieważ masz strukturę rekurencyjną, moją propozycją jest spłaszczyć ją za pomocą RecursiveIteratorIterator. Zakładając, że dane są w zmiennej o nazwie $xml, rozwiązanie może wyglądać mniej więcej tak:

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

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

$breadcrumb = array_reverse($breadcrumb); 
+0

to nie działa – Luca

+2

Przeczytaj mój komentarz powyżej, poprosiłem o opublikowanie xml, dzięki czemu mógłbym przetestować. Bardzo trudno jest dostarczyć idealną odpowiedź roboczą bez przykładowych danych! – quickshiftin

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

produkcja w przeglądarce:

Sport e tempo libero> Kategoria> Calcio> Abbigliamento> Bambine e ragazze
Sport e tempo libero> Kategorie> Calcio> Abbigliamento> Bambine e ragazze
(druga linia z łączami)

Wygenerowany kod 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> 
0

Naprawiono jedną odpowiedź powyżej - powinieneś unikać global, jeśli możesz.

Więc kod będzie

$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); 
Powiązane problemy