Frage

Wie baut man einen hierarchischen Satz von Tags mit Daten in PHP?

Zum Beispiel kann eine verschachtelte Liste:

<div>
    <ul>
        <li>foo
        </li>
        <li>bar
            <ul>
                <li>sub-bar
                </li>
            </ul>
        </li>
    </ul>
</div>

Dies wäre aus flachen Daten wie folgt aufbauen:

nested_array = array();
nested_array[0] = array('name' => 'foo', 'depth' => 0)
nested_array[1] = array('name' => 'bar', 'depth' => 0)
nested_array[2] = array('name' => 'sub-bar', 'depth' => 1)

Es wäre schön, wenn es schön wie das Beispiel formatiert wurde, zu.

War es hilfreich?

Lösung

Edit: Hinzugefügt Formatierung

Wie bereits in den Kommentaren, ist Ihre Datenstruktur etwas seltsam. Anstelle von Textmanipulation verwendet (wie OIS), ziehe ich DOM:

<?php

$nested_array = array();
$nested_array[] = array('name' => 'foo', 'depth' => 0);
$nested_array[] = array('name' => 'bar', 'depth' => 0);
$nested_array[] = array('name' => 'sub-bar', 'depth' => 1);
$nested_array[] = array('name' => 'sub-sub-bar', 'depth' => 2);
$nested_array[] = array('name' => 'sub-bar2', 'depth' => 1);
$nested_array[] = array('name' => 'sub-sub-bar3', 'depth' => 3);
$nested_array[] = array('name' => 'sub-sub3', 'depth' => 2);
$nested_array[] = array('name' => 'baz', 'depth' => 0);

$doc = new DOMDocument('1.0', 'iso-8859-1');
$doc->formatOutput = true;
$rootNode = $doc->createElement('div');
$doc->appendChild($rootNode);

$rootList = $doc->createElement('ul');
$rootNode->appendChild($rootList);

$listStack = array($rootList); // Stack of created XML list elements
$depth = 0; // Current depth

foreach ($nested_array as $nael) {
    while ($depth < $nael['depth']) {
        // New list element
        if ($listStack[$depth]->lastChild == null) {
            // More than one level at once
            $li = $doc->createElement('li');
            $listStack[$depth]->appendChild($li);
        }
        $listEl = $doc->createElement('ul');
        $listStack[$depth]->lastChild->appendChild($listEl);
        array_push($listStack, $listEl);

        $depth++;
    }

    while ($depth > $nael['depth']) {
        array_pop($listStack);
        $depth--;
    }

    // Add the element itself
    $li = $doc->createElement('li');
    $li->appendChild($doc->createTextNode($nael['name']));
    $listStack[$depth]->appendChild($li);
}

echo $doc->saveXML();

Ihre Formatierung Konvention ist irgendwie seltsam. Ersetzen Sie die letzte Zeile mit dem folgenden zu erreichen, ist es:

printEl($rootNode);

function printEl(DOMElement $el, $depth = 0) {
    $leftFiller = str_repeat("\t", $depth);
    $name = preg_replace('/[^a-zA-Z]/', '', $el->tagName);

    if ($el->childNodes->length == 0) {
        // Empty node
        echo $leftFiller . '<' . $name . "/>\n";
    } else {
        echo $leftFiller . '<' . $name . ">";
        $printedNL = false;

        for ($i = 0;$i < $el->childNodes->length;$i++) {
            $c = $el->childNodes->item($i);

            if ($c instanceof DOMText) {
                echo htmlspecialchars($c->wholeText);
            } elseif ($c instanceof DOMElement) {
                if (!$printedNL) {
                    $printedNL = true;
                    echo "\n";
                }
                printEl($c, $depth+1);
            }
        }

        if (!$printedNL) {
            $printedNL = true;
            echo "\n";
        }

        echo $leftFiller . '</' . $name . ">\n";
    }

}

Andere Tipps

Ich habe eine Frage, in Bezug auf Ihre Frage, die zu aufwendig für ein Kommentarfeld ist.

Wie Sie Attributdaten in das passen wollen? Sie müssten eine Whory Table ™ wie

array('html', null, array (
  array( 'div' , null , array( 
    array('ul', array('id'=>'foo'), array( 
      array('li', null, 'foo' ),
        array('li', null, array( 
          array(null,null, 'bar'), 
          array('ul', null, array( 
            array('li', null, 'sub-bar' )
          ))
        ))
      ))
    ))
  ))
));

da, dass die minimale Struktur ist erforderlich, um genau eine HTML-Dataset programmatisch darstellen.

Ich habe ein bisschen, indem die Notwendigkeit für „text-Knoten“ Elemente ganz so viel, betrogen, indem sie die Annahme, wenn

array (Name, Attribut, Kinder)

einen String hat anstelle eines Arrays für ‚Kinder‘ dann seine impliziter Text-Knoten, und dass die Knoten mit dem Namen == null sind die Tags nicht haben und sind damit auch Textknoten.

Was ich glaube, Sie wollen ein richtiges programmatischen DOM-Generierungs-Tool, das einen bestehenden HTML-Code in einen Baum analysieren wird Ihr Leben einfacher

machen

FWIW, kann die obige Struktur in HTML serialisiert werden ziemlich leicht.

function tohtml( $domtree ){ 
   if( is_null($domtree[0]) ){ 
     if( !is_array($domtree[2])){ 
         return htmlentities($domtree[2]);
     }
     die("text node cant have children!"); 
   }
   $html = "<" . $domtree[0]; 
   if( !is_null( $domtree[1] ) )
   {
     foreach( $domtree[1] as $name=>$value ){ 
       $html .= " " . $name . '="' . htmlentities($value) . '"'; 
     }
   }
   $html .= ">" ; 
   if( !is_null($domtree[2]) ){
     if( is_array($dometree[2]) ){ 
        foreach( $domtree[2] as $id => $item ){ 
          $html .= tohtml( $item ); # RECURSION
        } 
     }
     else {
       $html .= htmlentities($domtree[2]);
     }
  }
  $html .= "</" . $domtree[1] . ">"; 
  return $html; 
}

Sie meinen, so etwas wie

function array_to_list(array $array, $width = 3, $type = 'ul', $separator = ' ', $depth = 0)
{
    $ulSpace = str_repeat($separator, $width * $depth++);
    $liSpace = str_repeat($separator, $width * $depth++);
    $subSpace = str_repeat($separator, $width * $depth);
    foreach ($array as $key=>$value) {
        if (is_array($value)) {
        $output[(isset($prev) ? $prev : $key)] .= "\n" . array_to_list($value, $width, $type, $separator, $depth);
        } else {
            $output[$key] = $value;
            $prev = $key;
        }
    }
    return "$ulSpace<$type>\n$liSpace<li>\n$subSpace" . implode("\n$liSpace</li>\n$liSpace<li>\n$subSpace", $output) . "\n$liSpace</li>\n$ulSpace</$type>";
}

echo array_to_list(array('gg', 'dsf', array(array('uhu'), 'df', array('sdf')), 'sdfsd', 'sdfd')) . "\n";

erzeugt

<ul>
   <li>
      gg
   </li>
   <li>
      dsf
      <ul>
         <li>

            <ul>
               <li>
                  uhu
               </li>
            </ul>
         </li>
         <li>
            df
            <ul>
               <li>
                  sdf
               </li>
            </ul>
         </li>
      </ul>
   </li>
   <li>
      sdfsd
   </li>
   <li>
      sdfd
   </li>
</ul>

Ich weiß, Theres eine kleine Lücke da, wenn eine Unterliste nicht mit einer Erklärung beginnen.

Persönlich ich in der Regel nicht wirklich egal, wie die HTML aussieht, so lange seine leicht mit in PHP zu arbeiten.

Edit: OK, es funktioniert, wenn Sie es durch diese erste laufen ...: P

function flat_array_to_hierarchical_array(array &$array, $depth = 0, $name = null, $toDepth = 0)
{
    if ($depth == 0) {
        $temp = $array;
        $array = array_values($array);
    }
    if (($name !== null) && ($depth == $toDepth)) {
        $output[] = $name;
    } else if ($depth < $toDepth) {
        $output[] = flat_array_to_hierarchical_array(&$array, $depth + 1, $name, $toDepth);
    }
    while ($item = array_shift($array)) {
        $newDepth = $item['depth'];
        $name = $item['name'];
        if ($depth == $newDepth) {
            $output[] = $name;
        } else if ($depth < $newDepth) {
            $output[] = flat_array_to_hierarchical_array(&$array, $depth + 1, $name, $newDepth);
        } else {
            array_unshift($array, $item);
            return $output;
        }
    }
    $array = $temp;
    return $output;
}

$arr = flat_array_to_hierarchical_array($nested_array);
echo array_to_list($arr);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top