Есть ли простой способ преобразовать структуру XML в дерево для хранения в базе данных? - PullRequest
2 голосов
/ 11 января 2012

В частности, я хочу преобразовать структуру XML в этот формат для базы данных, чтобы я мог использовать измененный обход дерева предзаказа:

структура базы данных 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-скрипт на данный момент:

<code><?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 '
'; ?>

Я использую эту статью SitePoint для справки http://www.sitepoint.com/hierarchical-data-database-2/

Edit:

Пересмотренный скрипт 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 ]

2 голосов
/ 11 января 2012

Общий подход здесь состоит в том, чтобы создать список смежности (дерево), затем пройти по дереву, присваивая 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 |
+----------------------+----------------------+-----+-----+

Для получения дополнительной информации о вложенных наборах см. Работу Джо Селко:

0 голосов
/ 11 января 2012

Для этого следует рассмотреть расширение XQuery PHP: http://www.zorba -xquery.com / site2 / html / php.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...