根据可变深度数据生成嵌套 UL

发布于 2025-01-05 18:43:30 字数 2781 浏览 1 评论 0原文

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

I have some hierarchical data that I need to display in a series of nested UL's. For each item I have a name, an ID, and a depth value. Normally I would just group these items by depth, but I actually need to create a tree structure with my data, like this:
My sample data in MySQL Workbench

Here is my question: is there a good way to generate valid markup (I would love it if I could make it print out with proper tabbing too, but that will be tough) where my data will be wrapped in nested UL's? I already have a solution that kinda works, but I am getting a single stray

tag. Here is the code I have for that:

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

Any Ideas?

::Edit::
I have created a pastebin with the generated source which does not validate.
Pastebin.com

::EDIT 2::
Here is the schema for the Region table. It is designed using a hybrid of the nested set model and the adjacency list model.

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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

铁轨上的流浪者 2025-01-12 18:43:30

这应该有效:

$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;

获取修改后的预购树遍历模型(嵌套集)到

如何生成基于树遍历算法的结果集的树视图?

如何从这个结果集(嵌套类别存储在具有遍历模型的数据库中)?

This should work:

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

梅窗月明清似水 2025-01-12 18:43:30

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

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

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

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

Some time ago I come across the similar problem - a template to output a correct HTML tree.
Unfortunately, at the time I have at hand only a template itself, not the code preparing an array with data:

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

I'll try to find the code and post it here. Though it is not too complex. The main idea is to "unfold" a recursive tree to the plain list (with some "service" rows added contains no data to display but only tag markers ).

I wouldn't call it too nice solution but that was the best result I was able to get trying to separate business logic from display logic as much as possible.

The code can be simplified though as at the moment it supports link highlighting (it was intended to output site structure).

明媚殇 2025-01-12 18:43:30

我只想创建一个不错的列表。然后使用 CSS 格式化列表,请参阅示例。破折号可以用背景图像来完成。我使用了 level2.png(包含 1 个破折号)和 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>

I would just create a nice list. Then with CSS format the list, see example. The dashes can be done with background image. I used level2.png (contains one dash) and level3.png (contains 2 dashes).

level2.png

level3.png

The odd-even doesn't work 100% correct but the formatting of your list seems correct. You might consider adding more levels offcourse, it works the same way.

This way you have correct html, showing the relation between the data which makes it semantic. On the other side you have the flexibility to show it the way you want and it allows adding more data without additional formatting.

<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>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文