Генерация вложенных UL на основе данных переменной глубины - PullRequest
5 голосов
/ 15 февраля 2012

У меня есть некоторые иерархические данные, которые мне нужно отобразить в серии вложенных UL. Для каждого элемента у меня есть имя, идентификатор и значение глубины. Обычно я просто группирую эти элементы по глубине, но на самом деле мне нужно создать древовидную структуру с моими данными, например: 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>

Есть идеи?

:: Edit :: Я создал 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 ]

8 голосов
/ 28 февраля 2012

Это должно работать:

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

Получение модифицированной модели обхода дерева предзаказа (вложенный набор) в

    Как создатьдревовидное представление из этого набора результатов на основе алгоритма обхода дерева?

    Как создать массив из этого набора результатов (вложенные категории, хранящиеся в базе данных с моделью обхода)?

    0 голосов
    / 28 февраля 2012

    Некоторое время назад я столкнулся с похожей проблемой - шаблоном для вывода правильного 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 ?>
    

    Я постараюсь найти код и выложить его здесь.Хотя это не так уж сложно.Основная идея состоит в том, чтобы «развернуть» рекурсивное дерево в простой список (с некоторыми добавленными «служебными» строками, которые не содержат данных для отображения, а только маркерами тегов).

    Я бы не назвал это слишком хорошим решением, ноэто был лучший результат, который я смог получить, пытаясь максимально отделить бизнес-логику от логики отображения.

    Код можно упростить, хотя на данный момент он поддерживает подсветку ссылок (он был предназначен для вывода сайтаструктура).

    0 голосов
    / 15 февраля 2012

    Я бы просто создал хороший список. Затем с форматом 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>
    

    ...