<ul><li>-liste mit php erstellen

ColoredScy

ColoredScy

Mitglied
Thread Starter
Dabei seit
15.01.2004
Beiträge
78
Reaktionspunkte
0
hallo...

ich möchte aus einem mehrdimensionalen array eine html-liste erstellen (und bekomms weiss gott nicht auf die reihe, dass die tags an den richtigen stellen geschlossen werden).

folgendermaßen sieht mein array (vereinfacht) aus:

Code:
$meinarray = array
  (
     "name" => anzuzeigender name,
     "pos"  => wie weit eingerückt es sein soll,
     "fist" => 1 oder 0,
     "last" => 1 oder 0
  );
"first" und "last" sind jeweils "1", wenn der entsprechende eintrag der oberste/unterste in seiner hierarchie-ebene ist.

das ganze soll dann als <ul> ausgegeben werden - in etwa so:
Code:
0: A
1:   A.a
2:   A.b
3:     A.b.a
4:     A.b.b
5: B
6:   B.a

mein letzter entwurf dazu sieht wie folgt aus:
PHP:
$meinarray[] = array ("name"=>"A",     "pos"=>0, "first"=>1, "last"=>0);
$meinarray[] = array ("name"=>"A.a",   "pos"=>1, "first"=>1, "last"=>0);
$meinarray[] = array ("name"=>"A.b",   "pos"=>1, "first"=>0, "last"=>1);
$meinarray[] = array ("name"=>"A.b.a", "pos"=>2, "first"=>1, "last"=>0);
$meinarray[] = array ("name"=>"A.b.b", "pos"=>2, "first"=>0, "last"=>1);
$meinarray[] = array ("name"=>"B",     "pos"=>0, "first"=>0, "last"=>1);
$meinarray[] = array ("name"=>"B.a",   "pos"=>1, "first"=>1, "last"=>1);


print_r($meinarray);

function menuout($i=-1) {  // vorbelegung mit -1, da ich unten gleich um eins erhöhe und damit auf 0 als ausgangswert komme

    global $meinarray;
    
    $go=true; // keine schöne lösung, eine variable zum abbruch zu nehmen, aber ich war verzeifelt ;)
    
    while ($go) {
        
        $i++; // zähler erhöhen
    
        $j=$i;
        
        if ($meinarray[$i]['first']) { // jeder mit first gekennzeichnete eintrag startet mit einem <ul>
            echo "<ul>";    
        }

        echo "<li>"; // absolut jeder eintrag hat ein <li> vor seinem namen
        echo $meinarray[$i]['name'];
        
        if (isset($meinarray[($i+1)]) // sollte es den nächsten eintrag geben (ist bei dem letzten arrayeintrag nicht der fall)...
            && $meinarray[($i+1)]['first']) // und sollte dieser ein "first" sein (und damit ein neuer unterpunkt)...
                { 
                    $j = menuout(($i)); // ... dann soll die rekursion los gehen
                                        // j enthällt jetzt den rückgabewert, bei dem der letzte
                }
        
        echo "</li>";


        if ($meinarray[$i]['last']) { // sollte dieser eintrag als der letzte seiner hierarchie merkiert sein,
            echo "</ul>";             // dann </ul> ausgeben und die rekursion beenden
			return $i;
			$go=false;
        }
        
        if ($j>$i) { $i=$j; } // sollte sich j erhöht haben, so ist eine rekursion gelaufen und dessen zähler wird übernommen
        
        if ($i==sizeof($meinarray)) { $go=false; }
        

    }

}


menuout();

...nur leider funktionierts nicht ganz. ich habe in diesem versuch komplett nur mit den first/last gearbeitet, da bei ersten versuchen mit der positionsnummer nur noch falscheres bei mir raus kam:mad: - vill. kann mir ja jemand die augen öffnen oder weiss nen brauchbaren link/tipp für mich (hab leider selber keinen gefunden).
 
… ich hab zwar keinen Plan von nix, aber im
ersten Fenster steht "fist" statt "first" … das
denke ich gehört nicht so … oder?

Greetz,…
 
war nur ein tippfehler - ich bitte das zu ignorieren ;)
 
Warum so kompliziert?

Code:
<?php
$name = array ('A', 'A.a', 'A.a.a', 'A.b', 'B');
$position = array (1, 2, 3, 2, 1);

$pos = 1;
echo '<ul>';
for ($x=0; $x<count($name); $x++) {
	if ($position[$x] > $pos) {
		echo '<ul>';
		$pos = $position[$x];
	}
	echo '<li>' . $name[$x] . '</li>';
	if ($position[$x+1] < $pos) {
		echo '</ul>';
		$pos = $position[$x+1];
	}
}
echo '</ul>';
?>
 
dankeschön ;)

manchmal verbeisst man sich echt ganz schön in den holzweg, den man geht ;)
 
nachtrag - deine lösung funktioniert leider auch nicht fehlerfrei :(
und zwar immer dann, wenn ein sprung von mehr als einer ebene tiefe passert (kann zwar nicht beim tiefergehen vorkommen, aber beim zurückgehen).

Bsp.:
PHP:
$name = array ('A', 'AA', 'AA', 'AAA', 'B');
$position = array (1, 2, 2, 3, 1);

$pos = 1;
echo '<ul>';
for ($x=0; $x<count($name); $x++) {
	if ($position[$x] > $pos) {
		echo '<ul>';
		$pos = $position[$x];
	}
	echo '<li>' . $name[$x] . '</li>';
	if (!isset($position[$x+1]) || $position[$x+1] < $pos) {
		echo '</ul>';
		if (isset($position[$x+1])) { $pos = $position[$x+1]; }
	}
}
echo '</ul>';

(die 2x isset() hab ich nur rein, um fehler beim letzten eintrag zu vermeiden)


und noch ein nachtrag: ein untergeordnetes <ul> soll noch innerhalb des übergeordneten <li> stehen.

Bsp.:
Code:
<ul>
  <li>AAAAAAA</li>
  <li>BBBBBBB
     <ul>
        <li>CCCCC</li>
        <li>DDDDD</li>
     </ul>
  </li>
</ul>
 
Zuletzt bearbeitet:
ColoredScy schrieb:
nachtrag - deine lösung funktioniert leider auch nicht fehlerfrei :(
und zwar immer dann, wenn ein sprung von mehr als einer ebene tiefe passert (kann zwar nicht beim tiefergehen vorkommen, aber beim zurückgehen).

Mmh, das würde ich nicht mit so einem isset machen. Um in der Logik zu bleiben:
Ich habe $position mit $pos einfach per größer/kleiner verglichen. Mach das doch einfach mit absoluten Werten, d.h. x Ebenen Unterschied und setze dann eben x mal </ul> ein.

und noch ein nachtrag: ein untergeordnetes <ul> soll noch innerhalb des übergeordneten <li> stehen.

Dachte ich auch erst. Aber zumindest bei OmniWeb wurde dann noch ein zusätzlicher, häßlicher Spiegelstrich außen angezeigt. Schlag mal nach, ob <ul> in <ul> HTML-konform ist.

Wenn Du noch Probleme damit haben solltest, meld Dich einfach nochmal.

Viele Grüße
Jan-Kaspar
 
japp - <ul> innerhalb eines <li> ist konform. das ganze soll später mal ein popupmenü werden (klick mich ich bin ein beispiel).

und genau damit fangen die probleme an, da ich dann nicht einfach durchzählen kann, weil immer mal ein </li> dazwishen sein kann, aber je nach menüstruktur eben nicht muss :(
 
Ich hab mich vor kurzem mal rangesetzt und die Navigation des XTC-Shops so umgearbeitet, das eine unsortierte, korrekt verschachtelte Liste hinten rauskommt.

Da das zum Posten etwas viel Code ist, hier mal der Verweis auf meinen dazugehörigen Blogeintrag, vielleicht ist es ja eine Anregung:
http://www.blogpotato.de/2006/11/16/xtc-und-semantisch-korrekter-code/

Matt
 
danke für deinen beitrag - ich konnte mein problem aber inzwischen dann doch lösen :)

so müsste das jetzt (vereinfacht) lauten (die pos-angabe im array brauche ich gar nicht - komme allein mit dem first/last aus):
PHP:
$meinarray[] = array ("name"=>"A",     "pos"=>0, "first"=>1, "last"=>0);
$meinarray[] = array ("name"=>"A.a",   "pos"=>1, "first"=>1, "last"=>0);
$meinarray[] = array ("name"=>"A.b",   "pos"=>1, "first"=>0, "last"=>1);
$meinarray[] = array ("name"=>"A.b.a", "pos"=>2, "first"=>1, "last"=>0);
$meinarray[] = array ("name"=>"A.b.b", "pos"=>2, "first"=>0, "last"=>1);
$meinarray[] = array ("name"=>"B",     "pos"=>0, "first"=>0, "last"=>1);
$meinarray[] = array ("name"=>"B.a",   "pos"=>1, "first"=>1, "last"=>1);




function menuout($i=-1) {
	global $meinarray;
	
	
	$go=true;
	
	while ($go) {
	
		$i++;
	
		$j=$i;
		

		if ($meinarray[$i]['first']) {
			echo "<ul>";	
		}
	
		echo "<li>".$meinarray[$i]['name'];
	
		
		if (isset($meinarray[$i+1]) && $meinarray[$i+1]['first']) {
			$j = menuout($i);
		}
		
		
		echo "</li>";


		if ($meinarray[$i]['last']) {
			echo "</ul>";
			if (isset($j) && $j>$i) {
				return $j;
			} else {
				return $i;
			}
			$go=false;
		}
		
		
		if ($j>$i) { $i=$j; }
		
		if ($i==sizeof($meinarray)) { $go=false; }
		

	}

}


menuout();
 
Zuletzt bearbeitet:
Schön, daß es jetzt geklappt hat. Die Position fand ich nur ein bißchen praktischer zu handhaben als first und last. Aber: warum nimmst Du diese $go-Variable und keine for-Schleife?

jkm
 
Ohne den Thread nochmal neu aufrollen zu wollen, die Lösung funktioniert ja:

Es ist doch theoretisch möglich das ganze ohne jegliche Positions/first/last-Einträge hinzubekommen.

Möchte nur eine Bestätigung, probieren werd ich's mal wann anders :)
 
Zumindest die Position wird man schon angeben müssen. Wie soll das Programm denn wissen, das in welcher Einrückung stehen soll? Die Einträge "A.b" etc. waren sicher nur Mustertext...
 
also das mit der $go muss ich noch raus nehmen - ist echt kein guter Stiel.

diese first/last hab ich verwendet, da sie mir in meinem array schon vorliegen (Grund ist der, dass der oberste/unterste Eintrag im finalen Menü bei mir ein anderen Style bekommen sollen und ich nicht möchte, das das bei jedem Aufruf neu berechnet werden muss).

freilich geht das auch ohne dieses first/last und nur mit der Position, aber so rum find ichs leichter ;)

hier noch mal für euch den code, wie ich die zwei angeben gesetzt habe:
PHP:
// beispielvorgabe:

$meinarray[] = array ("name"=>"A",     "pos"=>0);
$meinarray[] = array ("name"=>"A.a",   "pos"=>1);
$meinarray[] = array ("name"=>"A.b",   "pos"=>1);
$meinarray[] = array ("name"=>"A.b.a", "pos"=>2);
$meinarray[] = array ("name"=>"A.b.b", "pos"=>2);
$meinarray[] = array ("name"=>"B",     "pos"=>0);
$meinarray[] = array ("name"=>"B.a",   "pos"=>1);



// im folgenden wird dann first/last hinzuberechnet


// "first" ist immer dann true, wenn der aktuelle eintrag eine tiefere pos-angabe hat, als das vorhergehende element

$z=-1;
for ($i=0; $i<sizeof($meinarray); $i++) {
	if ($meinarray[$i]['pos']>$z) {
		$meinarray[$i]['first']=1;
	} else {
		$meinarray[$i]['first']=0;
	}
	$z=$meinarray[$i]['pos'];
}



// "last" ist immer dann der fall, wenn (das array von hinten nach vorne durchlaufend) eine positionstiefe zum ersten mal in einem unterbaum vorkommt.

$z=sizeof($meinarray)+1;
for ($j=0; $j<=$maxtiefe; $j++) {
	$y[$j]=1;
}
for ($i=sizeof($meinarray)-1; $i>=0; $i--) {
	if ( $meinarray[$i]['pos']!=$z && $y[$meinarray[$i]['pos']]==1) {
		$y[$meinarray[$i]['pos']]=0;
		$meinarray[$i]['last']=1;
	} else {
		$meinarray[$i]['last']=0;
	}
	if ($meinarray[$i]['first']==1) {
		$y[$meinarray[$i]['pos']]=1;
	}
	$z=$meinarray[$i]['pos'];
}



// die variable maxtiefe enthält dabei den wert der maximalen unterpunkt-tiefe
// in meinem fall ist das die 2 (0>1>2)
 
j.muennich schrieb:
Zumindest die Position wird man schon angeben müssen. Wie soll das Programm denn wissen, das in welcher Einrückung stehen soll? Die Einträge "A.b" etc. waren sicher nur Mustertext...

Ah ok, hatte das Array anders gesehen. Ich meinte die Struktur davon würde schon die Struktur des späteren Menüs wiedergeben. Da dem nicht so ist, braucht man schon eine Art Rang/Position, hast Du Recht.
 
Zurück
Oben Unten