从平面数据在 PHP 中构建分层 html 标签
Posted
技术标签:
【中文标题】从平面数据在 PHP 中构建分层 html 标签【英文标题】:Build hierarchical html tags in PHP from flat data 【发布时间】:2010-09-24 00:38:17 【问题描述】:如何在 php 中构建带有数据的分层标签集?
例如嵌套列表:
<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)
如果它的格式也像示例一样很好。
【问题讨论】:
您的数组中确实没有足够的数据来构建层次结构。脚本如何知道将“子栏”项目附加到“栏”?如果你再做一次嵌套,那它会是“子子吧”吗?深度值也有点没用。为什么不让你的数组也分层呢? 数组的顺序很重要,诀窍是从具有深度信息的平面数据构建层次结构。我将编辑标题以使其更加明显。 好的,那么确保子项正确附加到其各自父项的约定是什么?索引顺序?命名约定? 【参考方案1】:你的意思是这样的
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 中使用即可。
编辑:好的,如果你先运行它,它就可以工作......: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);
【讨论】:
这看起来像是分层嵌套数组的解决方案。一个很好的解决方案,但不适用于我的问题。【参考方案2】:编辑:添加格式
正如 cmets 中已经说过的,您的数据结构有些奇怪。我更喜欢 DOM,而不是使用文本操作(如 OIS):
<?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";
【讨论】:
【参考方案3】:我有一个问题,您的问题对于评论字段来说过于详尽。
您希望如何将属性数据放入其中?你需要一个 Whory Table™ 像
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'的数组,然后它是一个隐式文本节点, 并且名称 == 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;
【讨论】:
以上是关于从平面数据在 PHP 中构建分层 html 标签的主要内容,如果未能解决你的问题,请参考以下文章