Alex: Nested Sets - HTML-Listendarstellung

Guten Abend.

Auf http://develnet.org/40.html schreibt Herr Gorski zum Thema Nested Sets folgende Zeilen:

"Zusätzlich enthalten ist der Grad (level) - so ist es ein Leichtes, korrekte Einrückungen der Threads darzustellen."

Nach ersten Schritten mit diesem Modell vor einigen Monaten, gelang mir zwar ein funktionierendes Stück Code, um ein Array der Form...

Array (
    [0] => Array ( [title] => A, [level] => 1 )
    [1] => Array ( [title] => B, [level] => 2 )
    [2] => Array ( [title] => C, [level] => 2 )
    [3] => Array ( [title] => D, [level] => 3 )
    [4] => Array ( [title] => E, [level] => 2 )
)

... als Liste in HTML darzustellen:

o A                 <ul><li>A<ul>
  o B                 <li>B</li>
  o C                 <li>C<ul>
    o D                 <li>D</li></ul></li>
  o E                 <li>E</li></ul></li>
                    </ul>

Als "ein Leichtes" würde ich dieses Gehacke aber nicht bezeichnen. Nach längerer Programmierpause habe ich mir heute dieses Problem erneut vorgenommen und bin noch immer zu keiner einfacheren Lösung gekommen, was mich so langsam aber sicher in den Wahnsinn treibt. ;)

Daher meine Frage: Seh ich nur den Wald vor lauter Bäumen (sprich: die einfache Lösung) nicht oder soll sie das tatsächlich schon sein? %-)

Wer einen Blick auf den Quelltext wagen möchte: $tree ist ein Array der oben beschriebenen Form, in dem "level" die Verzweigungstiefe des Knotens angibt (siehe dazugehörige Listendarstellung).

function printTree (&$tree) {
    echo "<ul>\n";
    _printTree($tree, 1);
    echo "</ul>\n";
}

function _printTree (&$tree, $lvl) {
    static $pos = 0;
    if ($pos >= sizeof($tree)) {
        return;
    }

if ($lvl < $tree[$pos]['level']) {
        echo "<ul>";
        _printTree($tree, $lvl+1);
        echo "</ul></li>";
        _printTree($tree, $lvl);
    }
    else if ($lvl == $tree[$pos]['level']) {
        echo "<li>{$tree[$pos]['title']}\n";
        $pos++;
        if ($lvl >= $tree[$pos]['level']) {
            echo "</li>";
        }
        _printTree($tree, $lvl);
    }
}

Gruß, Alex.

  1. Hi,

    Auf http://develnet.org/40.html schreibt Herr Gorski zum Thema Nested Sets folgende Zeilen:

    "Zusätzlich enthalten ist der Grad (level) - so ist es ein Leichtes, korrekte Einrückungen der Threads darzustellen."

    Hat er ja auch Recht, der gute Mann.

    Nach ersten Schritten mit diesem Modell vor einigen Monaten, gelang mir zwar ein funktionierendes Stück Code, um ein Array der Form...

    Array (
        [0] => Array ( [title] => A, [level] => 1 )
        [1] => Array ( [title] => B, [level] => 2 )
        [2] => Array ( [title] => C, [level] => 2 )
        [3] => Array ( [title] => D, [level] => 3 )
        [4] => Array ( [title] => E, [level] => 2 )
    )

    Sehr schön, damit hast Du den schwierigen Teil schon hinter Dir.

    Als "ein Leichtes" würde ich dieses Gehacke aber nicht bezeichnen. Nach längerer Programmierpause habe ich mir heute dieses Problem erneut vorgenommen und bin noch immer zu keiner einfacheren Lösung gekommen, was mich so langsam aber sicher in den Wahnsinn treibt. ;)

    Ja, das kann ich mir gut vorstellen, Du hast mein Mitgefühl.

    Daher meine Frage: Seh ich nur den Wald vor lauter Bäumen (sprich: die einfache Lösung) nicht oder soll sie das tatsächlich schon sein? %-)

    Ich tippe auf den Wald ;-)

    [hier stand eine komplexe rekursive Funktion, die hab ich mal entsorgt]

    Du hast doch schon alles sortiert (ich gehe wegen dem A,B,C... einfach mal davon aus) und es steht sogar der Level dran. Zudem ist die Länge des Arrays, also die Anzahl der Einträge bekannt. So kannst Du nun linear in einem kleinem Schleifchen abklappern (Pseudocode, zu faul zum probieren):

    LEVEL = 0
    FOR(jeden Eintrag im Array){
      EINTRAG = Eintrag im Array
      IF(Level vom nächstem Eintrag > EINTRAG(LEVEL)){
        neue Liste anfangen
        neuer Listenpunkt
        drucke EINTRAG aus
        LEVEL = Level vom nächstem Eintrag
        continue
      }
      IF(Level vom nächstem Eintrag == EINTRAG(LEVEL)){
        neuer Listenpunkt
        drucke EINTRAG aus
        LEVEL = Level vom nächstem Eintrag
        continue
      }
      IF(Level vom nächstem Eintrag < EINTRAG(LEVEL)){
        aktuelle Liste beenden
        neuer Listenpunkt
        drucke EINTRAG aus
        LEVEL = Level vom nächstem Eintrag
        continue
      }
      return
    }

    (Kein Netz, kein doppelter Boden, nur Ablauf!)

    Ganz so einfach ist die Implementation natürlich nicht, aber es sollte auch dem Ungeübten keine allzu argen Kopfschmerzen bereiten.

    so short

    Christoph Zurnieden