具体来说,我想将XML结构转换为数据库的这种格式,以便我可以使用修改后的预订树遍历:
database structure http://sitepointstatic.com/graphics/table02.gif
我的XML结构看起来像这样:
<?xml version="1.0" standalone="yes"?>
<products>
<node>
<name>Top Membership</name>
<node>
<name>Middle Membership</name>
<node>
<name>Bottom Membership</name>
<node>
<name>Some content</name>
<node>
<name>Specific content</name>
</node>
</node>
</node>
</node>
</node>
我已经制作了一个PHP脚本来遍历XML结构并将我的名字丢弃,我只是在计算左右值时遇到了麻烦。我想我可能不得不改变我的遍历逻辑,以便每次都跟着一个叶子,然后再次返回并重新开始,而不是每次都触底每个分支。如果我能做到这一点,那么我认为左右计算会更容易。
到目前为止我的PHP脚本:
<?php
$node = new SimpleXMLElement(file_get_contents('products.xml'));
echo '<pre>';
function getRowData($node, $depth)
{
//Not a leaf
if(isset($node->node))
{
echo $node->name."\t\t\t($depth) parent, children: ".count($node->children())."\n";
foreach($node->node as $n)
getRowData($n, $depth + 1);
}
else //It's a leaf
echo $node->name."\t\t\t($depth) leaf\n";
}
getRowData($node->node, 1);
echo '</pre>';
?>
我正在使用此SitePoint文章作为参考http://www.sitepoint.com/hierarchical-data-database-2/
修改
修改后的PHP脚本更接近解决方案(并以更好的格式输出更多(可能相关)的数字):
<?php
$node = new SimpleXMLElement(file_get_contents('products.xml'));
echo '<table border="1">';
echo '
<tr>
<th>Name</th>
<th>Depth</th>
<th>Child num</th>
<th>Children</th>
<th>Ancestors</th>
<th>Total siblings</th>
<th>"Left"</th>
<th>Parent "Left"</th>
</tr>';
function getRowData($node, $depth = 1, $child_num = 1, $prior_nodes = 0, $sibling_total = 0, $parent_left = 0)
{
echo '<tr>';
echo '
<td>'.$node->name."</td>
<td>$depth</td>
<td>$child_num</td>
<td>".(count($node->children()) - 1)."</td>
<td>$prior_nodes</td>
<td>$sibling_total</td>";
$left = $parent_left + ($child_num == 1 ? 1 : ($child_num * 2) - 1);
echo "<td>$left</td>";
echo "<td>$parent_left</td>";
echo '</tr>';
$child_num = 1;
foreach($node->node as $n)
{
getRowData(
$n,
$depth + 1,
$child_num++,
$prior_nodes + (count($node->children()) - 1),
(count($node->children()) - 1),
$left
);
}
}
getRowData($node->node);
echo '</table>';
?>
答案 0 :(得分:2)
这里的一般方法是创建一个邻接列表(树)
遍历树,在你往下的路上分配lft
并在你的路上rgt
。
假设这个xml:
<?xml version="1.0" standalone="yes"?>
<products>
<node><name>Top Membership</name>
<node><name>Middle Membership</name>
<node><name>Bottom Membership 1</name></node>
<node><name>Bottom Membership 2</name>
<node><name>Some content</name>
<node><name>Specific content</name></node>
</node>
</node>
</node>
</node>
</products>
以下代码可以满足您的需求。
$root = simplexml_load_string($xml);
function nested_set($parent, $rows=array(), $counter=1) {
foreach ($parent->node as $node) {
$row = array(
'title' => (string) $node->name,
'parent' => (string) $parent->name,
'lft' => $counter++,
'rgt' => null,
);
list($rows, $counter) = nested_set($node, $rows, $counter);
$row['rgt'] = $counter++;
$rows[] = $row;
}
return array($rows, $counter);
}
function print_rows($rows) {
$sep = '+'.str_repeat('-', 22).'+'.str_repeat('-', 22).'+'.str_repeat('-', 5).'+'.str_repeat('-', 5).'+'."\n";
echo $sep;
echo vsprintf("| %-20s | %-20s | %3s | %3s |\n", array_keys($rows[0]));
echo $sep;
foreach ($rows as $row) {
echo vsprintf("| %-20s | %-20s | %3d | %3d |\n", array_values($row));
}
echo $sep;
}
list($rows, $counter) = nested_set($root);
// rows will be in reverse-traversal order
print_rows($rows);
输出将是:
+----------------------+----------------------+-----+-----+
| title | parent | lft | rgt |
+----------------------+----------------------+-----+-----+
| Bottom Membership 1 | Middle Membership | 3 | 4 |
| Specific content | Some content | 7 | 8 |
| Some content | Bottom Membership 2 | 6 | 9 |
| Bottom Membership 2 | Middle Membership | 5 | 10 |
| Middle Membership | Top Membership | 2 | 11 |
| Top Membership | | 1 | 12 |
+----------------------+----------------------+-----+-----+
有关嵌套集的更多信息,请参阅Joe Celko的工作:
答案 1 :(得分:0)
您应该考虑使用XQuery PHP扩展来执行此操作:http://www.zorba-xquery.com/site2/html/php.html