我正在尝试显示这种数组:
$nodes = array(
1 => array(
'title' => 'NodeLvl1',
'children' => array(),
),
2 => array(
'title' => 'NodeLvl1',
'children' => array(
1 => array(
'title' => 'NodeLvl2',
'children' => array(),
),
2 => array(
'title' => 'NodeLvl2',
'children' => array(
1 => array(
'title' => 'NodeLvl3',
'children' => array(),
),
2 => array(
'title' => 'NodeLvl3',
'children' => array(),
),
),
),
),
),
3 => array(
'title' => 'NodeLvl1',
'children' => array(),
),
);
像这样:
<ul>
<li>
NodeLvl1
</li>
<li>
NodeLvl1
<ul>
<li>NodeLv2</li>
...
</ul>
</li>
...
基本上是一个考虑到“children”属性的嵌套列表。到目前为止,我已经想出了这个:
class It extends RecursiveIteratorIterator{
protected
$tab = "\t";
public function beginChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
}
public function endChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth())."\n</ul>";
}
public function nextElement(){
echo str_repeat($this->tab, $this->getDepth() + 1).'<li>';
}
}
$it = new It(new RecursiveArrayIterator($nodes));
foreach($it as $key => $item)
echo $item;
哪种方式不正常:我将每个项目包裹在<ul>
之间,我不知道如何关闭<li>
...
有关如何使这项工作的任何想法?也可以获取所有数组属性(实际元素),而不仅仅是我的foreach()循环中的“title”属性?这可以用对象而不是数组来完成吗?
答案 0 :(得分:14)
你需要一个类迭代器吗?你可以用一个简单的函数来做到这一点......
function arrayToListHTML($array, $level = 0) {
static $tab = "\t";
if (empty($array)) return;
$tabs = str_repeat($tab, $level * 2);
$result = "{$tabs}<ul>\n";
foreach ($array as $i => $node):
$result .= "{$tabs}{$tab}<li>\n{$tabs}{$tab}{$tab}{$node['title']}\n".arrayToListHTML($node['children'], $level + 1)."{$tabs}{$tab}</li>\n";
endforeach;
$result .= "{$tabs}</ul>\n";
return $result;
}
将产生此输出:
<ul>
<li>
NodeLvl1
</li>
<li>
NodeLvl1
<ul>
<li>
NodeLvl2
</li>
<li>
NodeLvl2
<ul>
<li>
NodeLvl3
</li>
<li>
NodeLvl3
</li>
</ul>
</li>
</ul>
</li>
<li>
NodeLvl1
</li>
</ul>
这涵盖了您向我们展示的内容,但我不确定您对其他属性的含义。除了title
和children
之外,每个数组中还有更多属性吗?
答案 1 :(得分:4)
不要试图像foreach()中的数组一样使用类,而是考虑使用类来执行该函数。例如,以下代码将正确输出,但该函数在类中执行。
class It extends RecursiveIteratorIterator{
protected
$tab = "\t";
public function beginChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth())."<ul>\n";
}
public function endChildren(){
if(count($this->getInnerIterator()) == 0)
return;
echo str_repeat($this->tab, $this->getDepth)."\n</ul>";
}
public function nextElement(){
echo str_repeat($this->tab, $this->getDepth())."<li>".$this->current()."</li>\n";
}
}
$it = new It(new RecursiveArrayIterator($nodes));
foreach($it as $key => $item)
//echo $item;
//it will be better to write a function inside your custom iterator class to handle iterations
?>
答案 2 :(得分:3)
我会选择一个简单的递归函数,将数组展平为text / html格式:
function arrToList( $arr, $embedded = false ) {
$output = array();
if ( $embedded ) $output[] = '<li>';
$output[] = '<ul>';
foreach ( $arr as $key => $values ) {
$output[] = '<li>'.$values['title'].'</li>';
if ( $values['children'] ) {
$output[] = arrToList( $values['children'], true );
}
}
$output[] = '</ul>';
if ( $embedded ) $output[] = '</li>';
return implode(PHP_EOL, $output);
}
使用输入输出:
或实际代码:
<ul>
<li>NodeLvl1</li>
<li>NodeLvl1</li>
<li>
<ul>
<li>NodeLvl2</li>
<li>NodeLvl2</li>
<li>
<ul>
<li>NodeLvl3</li>
<li>NodeLvl3</li>
</ul>
</li>
</ul>
</li>
<li>NodeLvl1</li>
</ul>
干杯
答案 3 :(得分:3)
首先让我向你解释一些事情。你的数组有两个模板
title
和children
的解析方式不同我认为递归函数在这部分扮演着非常好的角色,而不是复杂逻辑。我们的递归函数必须能够分别处理这两种模式。
function arraytolist(Array $array) { //ensure what you receive is array
if(count($array)) { //only if it has some items
//In case the array has `title` index we encountered out PATTERN 2
if(isset($array['title'])) {
$o = "<li>";
$o .= $array['title']; //simply add the title
$o .= arraytolist($array['children']); //and pass the children to this function to verify again
$o .= "</li>";
} else { //if its a normal array, //PATTERN 1
$o = "<ul>";
foreach($array as $value) {
$n = "";
if(is_array($value)) { //in case its an array again,
//send it to this very same function so that it will return as output again
$n .= arraytolist($value);
} else {
$n .= "<li>$value</li>";
}
$o .= strlen($n) ? $n : ""; //if $n has something use it otherwise not
}
$o .= "</ul>"; //lets close the ul
}
return $o;
}
}
答案 4 :(得分:2)
您可以使用RecursiveCachingIterator来执行您想要的操作。这是一个例子,(来源:https://github.com/cballou/PHP-SPL-Iterator-Interface-Examples/blob/master/recursive-caching-iterator.php)
<?php
// example navigation array
$nav = array(
'Home' => '/home',
'Fake' => array(
'Double Fake' => array(
'Nested Double Fake' => '/fake/double/nested',
'Doubly Nested Double Fake' => '/fake/double/doubly'
),
'Triple Fake' => '/fake/tripe'
),
'Products' => array(
'Product 1' => '/products/1',
'Product 2' => '/products/2',
'Product 3' => '/products/3',
'Nested Product' => array(
'Nested 1' => '/products/nested/1',
'Nested 2' => '/products/nested/2'
)
),
'Company' => '/company',
'Privacy Policy' => '/privacy-policy'
);
class NavBuilder extends RecursiveIteratorIterator {
// stores the previous depth
private $_depth = 0;
// stores the current iteration's depth
private $_curDepth = 0;
// store the iterator
protected $_it;
/**
* Constructor.
*
* @access public
* @param Traversable $it
* @param int $mode
* @param int $flags
*/
public function __construct(Traversable $it, $mode = RecursiveIteratorIterator::SELF_FIRST, $flags = 0)
{
parent::__construct($it, $mode, $flags);
// store the caching iterator
$this->_it = $it;
}
/**
* Override the return values.
*
* @access public
*/
public function current()
{
// the return output string
$output = '';
// set the current depth
$this->_curDepth = parent::getDepth();
// store the difference in depths
$diff = abs($this->_curDepth - $this->_depth);
// get the name and url of the nav item
$name = parent::key();
$url = parent::current();
// close previous nested levels
if ($this->_curDepth < $this->_depth) {
$output .= str_repeat('</ul></li>', $diff);
}
// check if we have the last nav item
if ($this->hasNext()) {
$output .= '<li><a href="' . $url . '">' . $name . '</a>';
} else {
$output .= '<li class="last"><a href="' . $url . '">' . $name . '</a>';
}
// either add a subnav or close the list item
if ($this->hasChildren()) {
$output .= '<ul>';
} else {
$output .= '</li>';
}
// cache the depth
$this->_depth = $this->_curDepth;
// return the output ( we could've also overridden current())
return $output;
}
}
?>
<强>用法强>
<?php
try {
// generate the recursive caching iterator
$it = new RecursiveCachingIterator(new RecursiveArrayIterator($nav));
// build the navigation with the iterator
$it = new NavBuilder($it, RecursiveIteratorIterator::SELF_FIRST);
// display the resulting navigation
echo '<ul id="nav">' . PHP_EOL;
foreach ($it as $value) {
echo $value . "\n";
}
echo '</ul>' . PHP_EOL;
} catch (Exception $e) {
var_dump($e); die;
}
?>