【问题标题】:Generate Nested UL's Based Upon Variable Depth Data根据可变深度数据生成嵌套 UL
【发布时间】:2012-03-06 05:20:22
【问题描述】:

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

这是我的问题:是否有一种生成有效标记的好方法(如果我也可以使用适当的制表符将其打印出来,我会喜欢它,但这会很困难)我的数据将被包裹在嵌套的 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;

【问题讨论】:

  • 您可以发布Region 表的数据库架构吗?
  • 我已为您添加了该架构。
  • 好的,我已经用你的架构编辑了我的答案。

标签: php html loops markup nested


【解决方案1】:

这应该可行:

$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)?

【讨论】:

  • 这个输出看起来很不错,但不幸的是它没有生成有效的标记。
  • 如果你想要一个性感的代码,你也可以处理缩进=D
  • 我使用php.net/manual/en/tidy.parsestring.php添加了缩进
  • 还删除了 PHP_EOL,因为整洁的解析器已经添加了它。
  • 哦...是的...我知道。我只是……确保你注意了!是的,就是这样……
【解决方案2】:

前段时间我遇到了类似的问题 - 一个输出正确 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 ?>

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

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

代码可以简化,但目前它支持链接突出显示(它旨在输出站点结构)。

【讨论】:

    【解决方案3】:

    我只想创建一个不错的列表。然后使用 CSS 格式化列表,请参见示例。破折号可以用背景图像完成。我使用了 level2.png(包含一个破折号)和 level3.png(包含 2 个破折号)。

    奇偶数不能 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>
    

    【讨论】:

    • 我的问题是关于生成有效标记,一旦我拥有它就不会显示它。由于我的数据集的复杂性,没有一种简单的方法来预测下一个项目的深度......它可能需要从当前项目缩进一站,或者可能需要少缩进两站。
    猜你喜欢
    • 1970-01-01
    • 2020-02-13
    • 2019-08-10
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 2022-01-20
    • 2017-04-04
    相关资源
    最近更新 更多