Rekursives Auslesen eines ungewöhnlichen Arrays (tricky!!!)

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Rekursives Auslesen eines ungewöhnlichen Arrays (tricky!!!)

    Hi Leute,

    ich muss ein Array auslesen und daraus eine verschachtelte HTML Liste bauen. Des besondere: Selbst Punkte, die auf gleicher Hierarchieebene liegen, sind Unterarrays. Das Parent Array Item von wirklichen Sub-Punkten befindet sich nach dem letzten Punkte der Subpunkte.

    Mit der unten aufgeführten Variante der Funktion buildList war ich am nähsten dran. Darin fehlt nun aber die Abfrage nach dem Parent. Das habe ich nie an die richtige Stelle bekommen. Es hing immer am letzten der Subpunkte.

    Genug der Worte - hier der Code (zur Verdeutlichung habe ich die Texte immer mit einer Nummerierung versehen):

    PHP-Code:
    <?php
    // The function that should render the HTML List
    function buildList($desc$ul 0) {
        
        if (
    $ul == 1) {

            
    $html[] = '<ul>';
        }

        
    $subs '';
        
    // if there is a subitem create a new ul within li
        
    if (is_array($desc['sub']) && count($desc['sub']) > 1) {

            
    $subs buildList($desc['sub'], 1);

        }

        
    $html[] = '<li>'.$desc['text'].$subs.'</li>';

        
    // We found a next item
        
    if (is_array($desc['next']) && count($desc['next']) > 0) {

            
    $html[] = buildList($desc['next'], 0);

        }

        if (
    $ul == 1) {
            
    $html[] = '</ul>';
        }

        return 
    implode(chr(10), $html);
    }


    // It's all about this array
    $descriptions = array (

        
    'next' => array (

            
    'next' => array (

                
    'next' => array(

                    
    'next' => array(

                        
    'next' => array(

                            
    'next' => '',
                            
    'parent' => '',
                            
    'sub' => '',
                            
    'text' => '6) blabla blubb',
                        ),
                        
    'parent' => '',
                        
    'sub' => '',
                        
    'text' => '5) blabla blubb',
                    ),
                    
    'parent' => '',
                    
    'sub' => '',
                    
    'text' => '4) blabla blubb',
                ),
                
    'parent' => '',
                
    'sub' => array(

                    
    'next' => array(

                        
    'next' => array(

                            
    'next' => '',
                            
    'parent' => array (

                                
    'text' => '3) blabla blubb'
                            
    ),
                            
    'sub' => '',
                            
    'text' => '3.3) blabla blubb',
                        ),
                        
    'parent' => '',
                        
    'sub' => '',
                        
    'text' => '3.2) blabla blubb',
                    ),
                    
    'parent' => '',
                    
    'sub' => '',
                    
    'text' => '3.1) blabla blubb',

                
    #'text' => '' // kein text bei dem item, wo wir einen sub eintrag haben, denn parent steht dann am Ende der Kette
                
    ),
            ),
            
    'parent' => '',
            
    'sub' => '',
            
    'text' => '2) blabla blubb',
        ),
        
    'parent' => '',
        
    'sub' => '',
        
    'text' => '1) blabla blubb',
    );


    // Let's go!
    $list buildList($descriptions1);

    echo 
    '<pre>';
    print_r($list);
    echo 
    '</pre>;
    ?>

    Ich freue mich über jede Art von Hilfestellung. Danke!
    Jochen

    P.S.: Mir steht PHP5 5.2.0 und 5.0.3 zur Verfügung, falls das was zur Sache tut.

  • #2
    Wenn die Struktur des Arrays nicht vorgegeben ist, dann wirf das weg und überlege dir eine bessere. Die jetzige versteht keiner, du ja selbst auch nicht.
    Die Idee mit next führt dazu, dass man das Array rückwärts aufbauen muß und parent ist völlig überflüssig, wenn man damit nicht die Werte des Elternelements überschreiben kann. Denn für die Abbildung der Verschachtelung hast du sub.

    Kommentar


    • #3
      Hallo,

      dein Problem ist folgendes...

      Wenn du das sub Array findest, rufst du die Funktion erneut auf, um ein neues ul Element(Unterliste) mit allen subs zu bilden und es in $sub zu speichern...
      // if there is a subitem create a new ul within li
      if (is_array($desc['sub']) && count($desc['sub']) > 1) {

      $subs = buildList($desc['sub'], 1);

      }
      ... danach, auf der Ebene von der du die Funktion erneut aufgerufen hast, willst du das in $sub gespeicherte ul Element in die Oberliste einfügen...

      $html[] = '<li>'.$desc['text'].$subs.'</li>';
      Du vergisst hier, das $desc['text'] leer ist, da es sich um das Array handelt, wo das sub Array enthalten ist und der Parent Text auf der tiefsten Ebene des Arrays ist. Deswegen wird dir der Punkt auch nicht angezeigt.
      Du müsstest also, bevor du die Unterliste erstellst, erstmal ganz nach unten laufen, den Parent Text hochholen. Dann li öffnen, Parent Text rein, Unterliste erstellen, Unterliste rein, /li schließen.

      Kann da meinem Vorredner nur zustimmen, das alles sehr ungünstig gelöst.

      Kommentar


      • #4
        Was hältst du von dieser Struktur?
        PHP-Code:
        $menu = array(
            
        'prefix' => '<div>',
            
        'suffix' => '</div><hr />',
            
        'base' => '/foo',
            
        'attributes' => array('class' => 'menu''id' => 'main-nav')
        );
        $menu[0] = array(
            
        'title' => 'Blabla',
            
        'url' => '/bla',
            
        'attributes' => array('title' => 'Alles über Blabla'),
        );
        $menu[0][0] = array(
            
        'title' => 'Sub Blabla',
            
        'url' => '/bla/sub',
        );
        $menu[0][1] = array(
            
        'title' => 'Sub 2 Blabla',
            
        'url' => '/bla/sub2',
        );
        $menu[1] = array(
            
        'title' => 'Blubb',
            
        'url' => '/blubb',
        ); 
        Sie soll zu dieser Ausgabe führen:
        Code:
        <div>
          <ul class="menu" id="main-nav">
            <li><a href="/foo/bla" title="Alles über Blabla">Blabla</a>
              <ul>
                <li><a href="/foo/bla/sub">Sub Blabla</a></li>
                <li><a href="/foo/bla/sub2">Sub 2 Blabla</a></li>
              </ul>
            </li>
            <li><a href="/foo/blubb">Blubb</a></li>
          </ul>
        </div><hr />
        Die Funktion, die das rendert, ist leicht zu schreiben. Und die Struktur ist leicht um weitere Schlüssel erweiterbar.

        Kommentar


        • #5
          Hi zusammen,

          vielen Dank schon mal für eure Vorschläge und Anregungen.

          Natürlich ist das Array so vorgegeben. *würg* Sonst hätte ich das Problem sicherlich nicht. Es ist das Ergebnis eines Soap Requests, auf den ich leider keinen weiteren Einfluss habe.

          Muss mich also durchkämpfen.

          Okay, letztlich muss ich wohl ein Flag setzen, wenn ich SUB finde und dann bis zu PARENT marschieren, um sämtliche NEXTs zu "sammeln" und dann "Unten angekommen"-Flag samt PARENT und SUBs TEXTe values zusammengesetzt rückübergeben... hui (!?)

          Frage mich nur, ob's dann auch bei verschachtelten SUBs funktioniert!? Irgendwie muss ich mir ja die Stelle merken, an der der aktuelle SUB-Zweig begann... bin da gerade noch etwas planlos und verwirrt.

          Werde mal weiter probieren, für weitere Anregungen bin ich natürlich dennoch dankbar!

          Cheers and have a nice sunday,
          Jochen

          Kommentar


          • #6
            Möglicherweise ist es einfacher, die SOAP-Antwort erstmal in eine bessere Struktur zu transformieren.
            Mir ist immer noch nicht klar, was das mit parent soll. Daher ist dieser Vorschlag vielleicht auch unbrauchbar.

            Kommentar


            • #7
              Die Soap Antwort in eine bessere Struktur zu bringen ist eigentlich genau das, was ich möchte! Ob ich da nun gleich eine HTML Liste draus bastele oder erst ein anderes Array ist dabei erstmal nicht so wichtig.

              Das mit dem Parent ist MEGA ätzend gelöst! Es hängt am letzten NEXT des SUB Arrays. Die Subs sind die Punkte 3.1, 3.2, 3.3 ... und an 3.3 hängt dieses PARENT-Attribut, seines Zeichens ein Array, den Text beinhaltend für Punkt 3.

              Ich glaube, ich habe aber eine Lösung im Kopf... mit 'ner Extra getParentFromSubNode Funktion oder so. Werde die Lösung dann posten, wenn es geklappt hat.

              Cheers,
              Jochen

              Kommentar


              • #8
                Evtl. kannst du auch einen dritten Zustand einführen.
                // if there is a subitem create a new ul within li
                if (is_array($desc['sub']) && count($desc['sub']) > 1) {

                // neuer Zustand
                $desc['text'] = buildList($desc['sub'],3);

                $subs = buildList($desc['sub'], 1);

                }
                Du müsstest dann sicherstellen das der dritte Zustand NICHTS macht, außer bis ganz nach unten zu laufen und den Parent text zu returnen.
                Dann weist du den Text $desc['text'] zu, da die Variable ja eh noch nicht beschrieben ist. Danach könntest du alles so weiterlaufen lassen wie es bis jetzt ist. Dir fehlt ja nur der Parent text, sonst ist ja alles ok

                Kommentar


                • #9
                  Neue Funktion ist wahrscheinlich sauberer, glaube du bist auf dem richtigen Weg

                  Kommentar


                  • #10
                    Jo, hab's!

                    Hier mal rough and dirty:

                    PHP-Code:
                    <?php
                    function getParentTextFromSubNode($node) {

                        if (
                    is_array($node['next']) && count($node['next']) > 0) {

                            return 
                    getParentTextFromSubNode($node['next']);

                        } elseif (
                    is_array($node['parent']) && $node['parent']['text'] != '') {

                            return 
                    $node['parent']['text'];

                        } else {

                            die(
                    'getParentTextFromSubNode... Error - no parent text found');

                        }

                    }
                    ?>
                    Die Funktion getParentTextFromSubNode durchläuft das übergebene Stück Array so lange, bis sie eben am letzten NEXT auf PARENT stößt.

                    PHP-Code:
                    <?php
                    function buildList($desc$ul 0) {

                        
                    // Let's initialize the used vars
                        
                    $parentText '';
                        
                    $subs '';

                        if (
                    $ul == 1) {

                            
                    $html[] = '<ul>';
                        }

                        
                    // if there is a subitem create a new ul within li
                        
                    if (is_array($desc['sub']) && count($desc['sub']) > 1) {

                            
                    // First we have to dig deep to get the subnode's parent text
                            
                    $parentText getParentTextFromSubNode($desc['sub'], 0);

                            
                    $subs buildList($desc['sub'], 1);

                        }

                        
                    $html[] = '<li>'.($parentText!=''?$parentText:$desc['text']).$subs.'</li>';

                        
                    // We found a next item
                        
                    if (is_array($desc['next']) && count($desc['next']) > 0) {

                            
                    $html[] = buildList($desc['next'], 0);

                        }

                        if (
                    $ul == 1) {
                            
                    $html[] = '</ul>';
                        }

                        return 
                    implode(chr(10), $html);
                    }
                    ?>
                    Und hier hole ich mir dann eben gleich den Parenttext und kann ihn schön VOR der Sublist einsetzen.

                    Und es funktioniert sogar, wenn das Array sich noch tiefer verschachtelt. Ich bin erleichtert!

                    Danke euch beiden. Turbo, vor allem Dein Satz:
                    Du müsstest also, bevor du die Unterliste erstellst, erstmal ganz nach unten laufen, den Parent Text hochholen.
                    hat mich dann letztlich auf den richtigen Weg gebracht.


                    Jochen

                    Kommentar


                    • #11
                      Ja sauber, freut mich!

                      Kommentar

                      Lädt...
                      X