我正在尝试使用封闭表存储的关系数据库内容,在PHP中构建层次结构数组。对于给定的结果,我将拥有LEAF
节点的完整路径,以下内容类似于我的结果集。
1〜root〜根节点
1〜root〜根节点>>> 2〜category1〜第一类
1〜root〜根节点>>> 3〜category2〜第二类
1〜root〜根节点>>> 2〜category1〜First category >>> 4〜Cat 1的subCatOfCategory1〜SubCategory
无论如何,这些是我的数据库结果。所以我想遍历它们并在PHP中构建层次结构,以便可以将其转换为JSON并在DOJO中呈现树
因此,当我遍历每一行时,我正在构建到叶子的“路径”,因为仅当元素是“叶”时才需要向树中添加元素...沿着这种想法,我决定将每个结果标记化,使用“>>>”作为分隔符,为我提供该行中的节点。然后,我遍历这些节点,并用“〜”标记每个节点,这为我提供了每个节点的属性。
因此,我有一个for循环来处理每个ROW,它基本上确定了如果要处理的节点不是叶子,则将其ID添加到要跟踪到达最终将要处理的叶子的路径的数组中。然后,当我最终到达LEAF时,可以使用在此过程中编译的PATH调用一个函数来插入节点。
希望一切都有意义..因此,我在下面包括了代码。.考虑上面的第二个结果。当我处理完整个结果并要调用函数insertNodeInTreeV2()时,数组如下所示...$fullTree
是具有1个元素的数组,索引为[1]
该元素包含一个包含四个元素的数组:ID(1)
,NAME(root)
,Description(the root node)
,CHILDREN(empty array)
$pathEntries
是一个只有一个元素(1)的数组。也就是说,要插入的LEAF节点的PATH是作为根节点的节点[1]的。$nodeToInsert
是一个包含四个元素的数组:ID(2)
,NAME(category1)
,Description(First Category)
,CHILDREN(empty array)
$treeRootPattern
是一个STRING,其中包含用于存储整个数组/树的变量名,在本例中为“fullTree”。
private function insertNodeInTreeV2( array &$fullTree, array $pathEntries, array $nodeToInsert, $treeRootPattern )
{
$compiledPath = null;
foreach ( $pathEntries as $path ) {
$compiledPath .= $treeRootPattern . '[' . $path . '][\'CHILDREN\']';
}
// as this point $compiledPath = "fullTree[1]['CHILDREN']"
$treeVar = $$compiledPath;
}
因此,当我进行赋值时,$ treeVar = $$ compiledPath ;,我想将变量$ treeVar设置为等于$ fullTree [1] ['CHILDREN'](已在调试器中验证此变量为有效数组)指数)。即使我将$ compiledPath的内容粘贴到Eclipse调试器中的新表达式中,它也会显示一个空数组,这很有意义,因为那是$ fullTree [1] ['CHILDREN']中的内容
但是相反,运行时告诉我以下错误...
如果您有更好的方法让我从我描述的结果集中获取要构建的层次结构数组,那么我将非常乐于采用更好的方法。
更新以添加调用上述功能的代码-数据库结果的循环过程行,如上文所述
foreach ( $ontologyEntries as $entry ) {
// iterating over rows of '1~~root~~The root node>>>2~~category1~~The first category
$nodes = explode( '>>>', $entry['path'] );
$numNodes = count( $nodes ) - 1 ;
$pathToNewNode = null; // this is the path, based on ID, to get to this *new* node
for ( $level = 0; $level <= $numNodes; $level++ ) {
// Parse the node out of the database search result
$thisNode = array(
'ID' => strtok($nodes[$level], '~~'), /* 1 */
'NAME' => strtok( '~~'), /* Root */
'DESCRIPTION' => strtok( '~~'), /* This is the root node */
'CHILDREN' => array()
);
if ( $level < $numNodes ) { // Not a leaf, add it to the pathToThisNodeArray
$pathToNewNode[] = $thisNode['ID'];
}
else {
// processing a leaf, add it to the array
$this->insertNodeInTreeV2( $$treeRootPattern, $pathToNewNode, $thisNode, $treeRootPattern );
}
}
}
最佳答案
请参阅您问题下方的我的评论以获取解释。
$paths = array(
"1~root~the root node",
"1~root~the root node>>>2~category1~First category",
"1~root~the root node>>>3~category2~Second category",
"1~root~the root node>>>2~category1~First category>>>4~subCatOfCategory1~SubCategory of Cat 1"
);
$tree = array();
foreach ($paths as $path)
{
$currentNode = &$tree;
$parts = explode(">>>", $path);
foreach ($parts as $part)
{
$node = explode("~", $part);
// create all nodes along this path
if (!isset($currentNode[$node[0]]))
{
$currentNode[$node[0]] = array(
"ID" => $node[0],
"NAME" => $node[1],
"DESCRIPTION" => $node[2],
"CHILDREN" => array(),
);
}
$currentNode = &$currentNode[$node[0]]["CHILDREN"];
}
}
var_dump($tree);
输出:
array
1 =>
array
'ID' => string '1' (length=1)
'NAME' => string 'root' (length=4)
'DESCRIPTION' => string 'the root node' (length=13)
'CHILDREN' =>
array
2 =>
array
'ID' => string '2' (length=1)
'NAME' => string 'category1' (length=9)
'DESCRIPTION' => string 'First category' (length=14)
'CHILDREN' =>
array
4 =>
array
'ID' => string '4' (length=1)
'NAME' => string 'subCatOfCategory1' (length=17)
'DESCRIPTION' => string 'SubCategory of Cat 1' (length=20)
'CHILDREN' => &
array
empty
3 =>
array
'ID' => string '3' (length=1)
'NAME' => string 'category2' (length=9)
'DESCRIPTION' => string 'Second category' (length=15)
'CHILDREN' =>
array
empty
该循环将创建路径中包含的所有节点,因此,如果您还插入
1~root~the root node
,则无需插入1~root~the root node>>>2~category1~First category
。如果该节点是路径的最后一个节点,则只能通过创建节点来更改此设置。路径的长度是
count($parts)
,您可以计算内部foreach循环中的级别。希望这就是您想要的。