如何使用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)
如果它的格式也很好,那就太好了。
答案 0 :(得分: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";
}
}
答案 1 :(得分: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>
如果子列表没有以解释开头,我知道那里有一点差距。
就个人而言,只要它易于在PHP中使用,我通常并不关心HTML的外观。
编辑:好的,如果你先通过这个来运行它......: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 :(得分:0)
我有一个问题,关于你的评论领域过于复杂的问题。
您希望如何适应属性数据?你需要像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;
}