从平面数组和结构化ID构建数组树

时间:2012-03-09 15:53:27

标签: php mysql html

如果你对问题的第二个问题感到困惑,请坚持下去,因为我不确定它是否真的有意义。

SELECT * FROM `rules` ORDER BY `Rank_1` , `Rank_2` , `Rank_3` , `Rank_4` ASC

收率:

http://img814.imageshack.us/img814/8396/climsyclipboardeh.png

复制意大利面:

0   0   0   0   0
1   0   0   0   1
1   1   0   0   1.1
1   1   1   0   1.1.1 
2   0   0   0   2
4   0   0   0   4
4   1   0   0   4.1
4   1   1   0   4.1.1 
4   1   1   9   4.1.1.9
4   1   1   10  4.1.1.10 
4   1   1   11  4.1.1.11

然而,这些数据并不是我需要的形式,以便用它做一些有用的事情。

我想循环遍历所有规则,并根据我的“深度”,做不同的事情。例如,我想使用RuleID = 0并执行<h1>,1.1使用<h2>但是当涉及到4.1.x时,请打开<ul>并为每个规则指定<li> 1}}。

为此,我认为最好的方法是选择数据,就像我最终得到的数组一样:

array( 4 =>
    array( 4.1 =>
        array( 4.1.1 => 'rule content')
    )
);

然后我可以实现自己的深度并打开<ul>标签,循环打印出那个深度的规则等。

解决这个问题的最佳方法是什么?我已经多年了,并且不知道从哪里开始说实话。我真的希望数据在同一个表中。我想我可以解决这个问题,如果他们都在不同的表格中,但我不知道这肯定会更容易。

我开始沿着这条路走下去:

foreach($m as $rule) {
    $depth = count(explode('.', $rule['ruleid']));
    switch($depth) {
        case 1:
            echo '<h1>'.$rule['content'].'</h1>';
            break;
        case 2:
            echo '<h2>'.$rule['content'].'</h2>';
            break;
        case 3:
            echo '<strong>'.$rule['content'].'</strong>';
            break;
    }
    echo '<br />\n';
}

然后我意识到这只是单独处理每个规则条目,而我的解决方案需要某种“意识”它在规则中的位置,因此它可以知道何时打开标记(例如{ {1}})然后在它完成回显规则中可能存在的列表项时再次关闭它(例如<ul>

以下是上述数据表中所需输出的示例:

  

0。引言

     

...

     

4。聊天

     

4.1。做和不做

     

4.1.1。做:

     
  • 4.1.1.9礼貌
  • 4.1.1.10耐心等待
  • 4.1.1.11聪明
希望一些明亮的火花可以帮助你!

4 个答案:

答案 0 :(得分:4)

假设您可以根据输入数据生成如下数组:

$data = array(
  '0'        => 'content 0',
  '1'        => 'content 1',
  '1.1'      => 'content 1.1',
  '1.1.1'    => 'content 1.1.1',
  '2'        => 'content 2',
  '4'        => 'content 4',
  '4.1'      => 'content 4.1',
  '4.1.1'    => 'content 4.1.1',
  '4.1.1.9'  => 'content 4.1.1.9',
  '4.1.1.10' => 'content 4.1.1.10',
  '4.1.1.11' => 'content 4.1.1.11',
);

然后你可以使用它来转换为树状结构:

// this will be our root node
// it has no content, but a place for children
$struct = array(
  'children' => array()
);

foreach ($data as $ruleID => $content) {
  //                 /\
  //                 ||
  //     for every rule id in the input data we start at
  //     the root
  //          ||
  //          \/
  $parent =& $struct;

  // we split $ruleID at the dot to get a path, which we traverse
  //            ||
  //            \/
  foreach (explode('.', $ruleID) as $val) {

    // for every entry in the path we
    // check if it's available in the current parent
    //    ||
    //    \/
    if (!isset($parent['children'][$val])) {
      // if not, we create an empty entry
      $parent['children'][$val] = array(
        'content' => '',       // no content
        'children' => array()  // no children
      );
    }

    //                         /\
    //                         ||
    // and then use either the new, or allready existent parent
    // as the new parent
    //      ||
    //      ||  mind the assignment by reference! this
    //      \/  is the most important part
    $parent =& $parent['children'][$val];
  }

  // after the whole path is traversed, we can
  // finally add our content
  //                    ||
  //                    \/
  $parent['content'] = $content;
}

print_r($struct);

演示:http://codepad.org/vtMPjGoa

答案 1 :(得分:1)

如果想要以可能破坏各种样式规则的方式混合HTML和SQL,可以添加“ruledepth”列,然后在其上使用“CASE”,例如:

SELECT othercols, 
CASE 
WHEN ruledepth=0 THEN CONCAT('<h1>', ruleid, '</h1>') 
WHEN ruledepth=1 THEN CONCAT('<h2>', ruleid, '</h2>') 
WHEN ruledepth=2 THEN CONCAT('<li>', rileid, '</li>')
etc
END FROM XXX WHERE .... ORDER BY ruleid........

答案 2 :(得分:1)

稍微修改OP代码。

您可以将$rule['ruleid']添加到echo语句中,使其与所需的输出完全相同。

$hasList=false;
foreach($m as $rule) {
    $depth = count(explode('.', $rule['ruleid']));
    // end previous list before starting with new rules
    if ($hasList && $depth<4) {
        echo '</ul>';
        $hasList=false;
    }
    switch($depth) {
        case 1:
            echo '<h1>'.$rule['content'].'</h1>';
            break;
        case 2:
            echo '<h2>'.$rule['content'].'</h2>';
            break;
        case 3:
            echo '<strong>'.$rule['content'].'</strong>';
            break;
        case 4:
            // start list if not already started
            if (!$hasList) {
                echo '<ul>';
                $hasList=true;
            }
            echo '<li>'.$rule['content'].'</li>';
            break;
    }
    //echo "<br />\n";
}
// end last list
if ($hasList) {
    echo '</ul>';
    $hasList=false;
}

答案 3 :(得分:0)

我不确定这是否正是你所需要的,但也许它会给你一些想法。

首先,您可以通过执行以下操作来确定规则的“深度”:

$depth = count(explode('.',$rule_id));

这将在.上拆分您的规则ID并创建一个数组。然后它计算数组中的项目以确定深度。