基于可变深度数据生成嵌套UL

时间:2012-02-14 20:26:24

标签: php html loops markup nested

我有一些分层数据需要在一系列嵌套的UL中显示。对于每个项目,我有一个名称,一个ID和一个深度值。通常我会按深度对这些项进行分组,但实际上我需要使用我的数据创建树结构,如下所示: My sample data in MySQL Workbench

这是我的问题:是否有一种很好的方法来生成有效的标记(如果我能用正确的标签打印出来,我会很喜欢它,但这很难)我的数据将被嵌套在UL中?我已经有一个有点工作的解决方案,但我得到一个单一的迷路标签。这是我的代码:

<?php
    include("includes/classes/Database.class.php");
    $db = new Database();
    $query = "SELECT COUNT(parent.Name) - 2 as level, node.Name AS Name, node.ID
    FROM Region AS node, Region AS parent
        WHERE node.LeftVal BETWEEN parent.LeftVal AND parent.RightVal and node.Name <> 'Earth'
            GROUP BY node.ID
            ORDER BY node.LeftVal";
    $results = $db->executeQuery($query);
?>
<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <?php
        $last_level = 0;
    ?>
    <ul id="regionTree">
    <?php
        while ($row = mysql_fetch_assoc($results)) {
            $link = '<li>'.PHP_EOL.'<a href="addChild.php?parentid='.$row["ID"].'">'.$row["Name"]."</a>".PHP_EOL;
            $diff = $last_level - $row["level"];
            if($diff == 0){
                // Sibling
                echo ($row["level"] != 0) ? '</li>'.PHP_EOL.$link:$link;
            }
            elseif($diff < 0){
                // Child
                $demoter = '<ul>'.PHP_EOL;
                for ($i=0; $i > $diff; $i--) { 
                    echo $demoter;
                }
                echo $link;
            }
            else{
                // Parent
                $promoter = '</li>'.PHP_EOL.'</ul>';
                for ($i=0; $i < $diff; $i++) { 
                    echo ($row["level"] != 0) ? $promoter.PHP_EOL."</li>":$promoter;
                }
                echo $link;
            }

            $last_level = $row["level"];
        }
    ?>
    </li>
    </ul>
</body>
</html>

任何想法?

::编辑:: 我用生成的源创建了一个不验证的pastebin。 Pastebin.com

::编辑2 :: 这是Region表的模式。它是使用嵌套集模型和邻接表模型的混合设计的。

CREATE TABLE Region (
    ID INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Stores the ID for the Region.',
    Name VARCHAR(45) NOT NULL COMMENT 'Stores the name of the Region',
    Region_Type VARCHAR(45) NOT NULL COMMENT 'Stores the Region type.',
    Parent INT COMMENT 'Stores the ID of the Parent Region',
    LeftVal INT NOT NULL,
    RightVal INT NOT NULL,
PRIMARY KEY (ID)
) COMMENT 'Stores information about all Regions.' ENGINE=INNODB
ROW_FORMAT=DEFAULT CHARACTER SET utf8 collate utf8_general_ci;

3 个答案:

答案 0 :(得分:8)

这应该有效:

$query = "SELECT node.Name, (COUNT( parent.Name ) -1) AS depth FROM region AS node
            CROSS JOIN region AS parent
                WHERE node.LeftVal BETWEEN parent.LeftVal
                    AND parent.RightVal
            GROUP BY node.Name
            ORDER BY node.LeftVal";

$result = mysql_query($query);

// Build array
$tree = array();
while ($row = mysql_fetch_assoc($result)) {
    $tree[] = $row;
}

// Bootstrap loop
$result        = '';
$currDepth     = 0; 
$lastNodeIndex = count($tree) - 1;
// Start the loop
foreach ($tree as $index => $currNode) {
    // Level down? (or the first)
    if ($currNode['depth'] > $currDepth || $index == 0) {
        $result .= '<ul>';
    }
    // Level up?
    if ($currNode['depth'] < $currDepth) {
        $result .= str_repeat('</ul></li>', $currDepth - $currNode['depth']);
    }
    // Always open a node
    $t = ($index == 0) ? 1 : 2;
    $result .= '<li>' . $currNode['Name'];
    // Check if there's chidren
    if ($index != $lastNodeIndex && $tree[$index + 1]['depth'] <= $tree[$index]['depth']) {
        $result .= '</li>'; // If not, close the <li>
    }
    // Adjust current depth
    $currDepth = $currNode['depth'];
    // Are we finished?
    if ($index == $lastNodeIndex) {
        $result .= '</ul>' . str_repeat('</li></ul>', $currDepth);
    }
}

// Indent the code
// For UTF8: tidy_parse_string($result, array('indent' => true, 'show-body-only' => true), 'UTF8')
$result = tidy_parse_string($result, array('indent' => true, 'show-body-only' => true));
print $result;

Getting a modified preorder tree traversal model (nested set) into a <ul>

How to generate a tree view from this result set based on Tree Traversal Algorithm?

How to create an array from this result set (nested categories stored in databased with traversal model)?

答案 1 :(得分:0)

前段时间我遇到了类似的问题 - 输出正确HTML树的模板 不幸的是,当时我手边只有一个模板,而不是准备带数据的数组的代码:

<? foreach ($TREE as $row): ?> 
<?   if($row['li']=="open"): ?>
<ul>
<?   endif ?> 
<?   if($row['li'] == "close"): ?>
</ul>
<?   endif ?> 
<?   if($row['id']): ?> 
<?     if($id == $row['id']): ?> 
  <li><?=$row['title']?></li> 
<?     else: ?> 
  <li><a href="?id=<?=$row['id']?>"><?=$row['title']?></a></li> 
<?     endif ?> 
<?   endif ?> 
<? endforeach ?>

我会尝试找到代码并在此处发布。虽然它不是太复杂。主要思想是将递归树“展开”到普通列表(添加了一些“服务”行,不包含要显示的数据,只包含标记标记)。

我不会称之为太好的解决方案,但这是我能够尽可能地将业务逻辑与显示逻辑分开的最佳结果。

代码可以简化,因为它支持链接突出显示(它旨在输出网站结构)。

答案 2 :(得分:-1)

我会创建一个很好的列表。然后用CSS格式列表,参见示例。破折号可以用背景图像完成。我用过level2.png(包含一个破折号)和level3.png(包含2个破折号)。

level2.png

level3.png

奇数偶数不能100%正确,但列表的格式似乎是正确的。您可以考虑在场外添加更多关卡,它的工作方式相同。

这样你就有了正确的html,显示了使它成为语义的数据之间的关系。另一方面,您可以灵活地按照自己的方式显示它,并且无需额外格式化即可添加更多数据。

<html>
<head>
    <style type="text/css">
        * {
            font-size: 11px;
            font-family: tahoma;
            background-repeat: no-repeat;
        }
        .odd {
            background-color: #ccc;
        }
        .even {
        }

        ul, li {
            width: 300px;
            padding: 0px;
            padding: 0px;
        }

        ul.level1 li span {
        }
        ul.level2 li span {
            padding-left: 50px;
            background-image: url(level2.png);
        }
        ul.level3 li span {
            padding-left: 100px;
            background-image: url(level3.png);
        }
    </style>
</head>
<body>
    <?PHP
        $i=0;
        echo '<ul class="level1">';
        for($x=0; $x<10; $x++) {
            echo '<li class="'.(($i%2) ? 'odd' : 'even').'"><span>level1-'.$i.'</span>';
            $i++;
                echo '<ul class="level2">';
                for($y=0; $y<10; $y++) {
                    $i++;
                    echo '<li class="'.(($i%2) ? 'odd' : 'even').'"><span>level2-'.$y.'</span>';
                        echo '<ul class="level3">';
                        for($z=0; $z<10; $z++) {
                            $i++;
                            echo '<li class="'.(($i%2) ? 'odd' : 'even').'"><span>level3-'.$z.'</span>';

                            echo '</li>';
                        }
                        echo '</ul>';
                    echo '</li>';
                }
                echo '</ul>';
            echo'</li>';
        }
        echo '</ul>';
    ?>
</body>