有没有一种简单的方法可以将XML结构转换为树来存储在数据库中?

时间:2012-01-11 11:22:07

标签: php mysql xml tree

具体来说,我想将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>';

?>

2 个答案:

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