2008-11-25 50 views
2

如何使用PHP中的數據構建分層標籤集合?從平面數據在PHP中構建分層html標籤

例如,一個嵌套列表:

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

這將是從這樣的平面數據建立:

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) 

這將是很好,如果它被很好地格式化像的例子了。

+0

您的數組中沒有足夠的數據來構建層次結構。腳本如何知道將「子欄」項目附加到「欄」?如果你做了另一個嵌套,它會成爲「子分欄」嗎?深度值也是無用的。 爲什麼不只是讓你的陣列分層呢? – 2008-11-25 19:28:28

+0

數組的排序是重要的,訣竅是從平面數據和深度信息構建層次結構。我將編輯標題以使其更加明顯。 – postfuturist 2008-11-25 19:34:21

+0

好的,那麼爲了確保子項目正確地附加到它們各自的父項目,約定是什麼?索引順序?命名約定? – 2008-11-25 19:37:14

回答

2

編輯:添加格式

正如已經在評論中說,您的數據結構有點奇怪。而不是使用文本操作(如OIS),我更喜歡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(); 

您的格式約定有點奇怪。將最後一行替換爲以下內容以實現它:

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"; 
    } 

} 
0

你的意思是這樣

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

產生

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

我知道那裏有一個小缺口,如果有一個子列表不解釋開始。

就我個人而言,我通常並不在乎HTML的外觀如何,只要它在PHP中易於使用。

編輯:OK,如果你通過這個先運行它,它的工作原理...: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); 
0

我有一個問題,關於您的問題對於評論字段來說太精細了。

你想如何適應屬性數據?你需要一個Whory表™像

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

,因爲這是準確地編程表示HTML數據集所需的最小結構。

我已經通過消除對「文本節點」的元素,需要相當多,通過使假設,如果

陣列(名稱,屬性,子女)

有一個字符串,而不是被騙了一下爲'children'的數組,然後它是一個隱含的文本節點, 並且name == null的節點沒有標籤,因此也是文本節點。

我想你想要的是一個適當的綱領性DOM生成工具,這將分析一些現有的HTML成樹,讓您的生活更輕鬆

FWIW,上述結構可序列化到HTML相當容易。

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