简体   繁体   English

PHP XML - 如何构建与父子关系处于同一级别的xml节点树

[英]PHP XML - How to build a tree of xml nodes that are at at same level with parent child relationship

I am trying to read the xml from a file and display them just like a tree. 我试图从文件中读取xml并像树一样显示它们。 I am using PHP and I want to get the output as shown below. 我正在使用PHP,我想得到如下所示的输出。 The content of xml file is as follows... xml文件的内容如下......

<Categories>

<Category>
  <Id>1</Id>
  <Name>Parent 1</Name>
  <ParentId>1</ParentId>
  <ParentName>Parent 1</ParentName>
</Category>
<Category>
  <Id>2</Id>
  <Name>Child 1</Name>
  <ParentId>1</ParentId>
  <ParentName>Parent 1</ParentName>
</Category>
<Category>
  <Id>3</Id>
  <Name>Child 2</Name>
  <ParentId>1</ParentId>
  <ParentName>Parent 1</ParentName>
</Category>
<Category>
  <Id>8</Id>
  <Name>Grand Child 1 -1</Name>
  <ParentId>2</ParentId>
  <ParentName>Child 1</ParentName>
</Category>

<Category>
  <Id>12</Id>
  <Name>Parent 2</Name>
  <ParentId>12</ParentId>
  <ParentName>Parent 2</ParentName>
</Category>

<Category>
  <Id>15</Id>
  <Name>Child 2-1</Name>
  <ParentId>12</ParentId>
  <ParentName>Parent 2</ParentName>
</Category>

  </Categories>
</CategoryList>

I want to read this xml file (I know how to read it) But I can not format it like follows... How would I get all the nodes that are the top most parents and get child of those parent nodes (using recursion or what so ever) 我想阅读这个xml文件(我知道如何阅读它)但是我不能像下面那样格式化它...我如何获得最多父节点的所有节点并获得这些父节点的子节点(使用递归或怎么样)

<ul>
<li>Parent 1
    <ul>
        <li> Child 1
            <ul>
                <li>Grand Child 1 -1</li>
            </ul>

        </li>
        <li> Child 2</li>
    </ul>

</li>
<li>Parent 2
    <ul>
        <li>Child 2-1 </li>
    </ul>

</li>

</ul>

Please any help will be greatly appreciated.... 请任何帮助将不胜感激....

Edit* What I have done so far... 编辑*到目前为止我做了什么......

$xml= simplexml_load_string('myxmlstring');

get_categories($xml, 0);

function get_categories($xml, $id) {

    if ($id==0) 
        $Categories = $xml->xpath('Categories/Category[ParentId=Id]');
    else
        $Categories = $xml->xpath('Categories/Category[ParentId='.$id.' and Id!='.$id.']');

    echo '<ul id="catlist'.$id.'">';
    foreach($Categories as $Category) {
        echo "<li>ID: " . $Category->Id . "--Name: " . $Category->Name;
        get_categories($xml, $Category->Id);
        echo "</li>";

    }
    echo "</ul>";
}

Now I just want to confirm that this is the optimal solution. 现在我只想确认这是最佳解决方案。 or someone can come with better idea... 或者有人可以提出更好的想法......

ParentName is excessive, it's enough to put just parent id. ParentName过多,只需放置父ID即可。

Since you do a search for each node, execution time will be O(N 2 ), where N is amout of nodes. 由于您搜索每个节点,因此执行时间将为O(N 2 ),其中N是节点的数量。

There's an option to do this in linear time, though: Firstly traverse data and build tree structure (or somewhat) and then traverse that structure and output nodes according to it. 但是,可以选择在线性时间内执行此操作:首先遍历数据并构建树结构(或稍微),然后根据它遍历该结构和输出节点。

Output buffering is also a good option here. 输出缓冲在这里也是一个不错的选择。

// init
$childrenReferences = array();
$rootNodes = array();
$xmlNodes = array();

// gathering structure
$cats = $xml->getElementsByTagName('Category');
for ($i = 0; $i < $cats->length; $i++) {
    $cat = $cats[$i];
    $id = $children->Id;
    $parentId = $cat->ParentId;
    $xmlNodes[$id] = $cat;
    if ($parentId == $id) {
        $rootNodes []= $id;
        continue;
    }
    if (array_key_exists($parentId, $childrenReferences)) {
        $childrenReferences[$parentId] []= $id;
    } else {
        $childrenReferences[$parentId] = array($id);
    }

}

// output
function out_nodes($nodes) {
    global $childrenReferences, $xmlNodes; // this is not required since php 5.3 or something about
    echo "<ul>";
    foreach ($nodes as $id) {
        $cat = $xmlNodes[$id];
        echo "<li>ID: " . $cat->Id . "--Name: " . $cat->Name;
        if (array_key_exists($id, $childrenReferences)) { // intermediate node
            out_nodes($childrenReferences[$id]);
        }
        echo "</li>";
    }
    echo "</ul>";
}

ob_start();
out_nodes($rootNodes);
ob_end_flush();

Code may not work or even compile, but you get the idea. 代码可能无法工作甚至编译,但你明白了。

Thanks kirilloid.... that was great help... I am using the code with some modifications... the xml is from curl and I know ParentName is excessive, but I've no control over it. 谢谢kirilloid ....这是很好的帮助...我正在使用代码进行一些修改... xml来自curl我知道ParentName过多,但我无法控制它。 Here is the final code.... 这是最终的代码......

$childrenReferences = array();
$rootNodesIDs = array();
$xmlNodes = array();

$dom = new DOMDocument;
$dom->loadXML($xml);

$Categories = $dom->getElementsByTagName('Category');
$length = $Categories->length;

for ($i = 0; $i < $length; $i++) {
    $cat = $Categories->item($i);           //Get the DOMNode 
    $id = $cat->getElementsByTagName('Id')->item(0)->nodeValue;
    $parentId = $cat->getElementsByTagName('ParentId')->item(0)->nodeValue;
    $xmlNodes[$id] = $cat;      

    if ($parentId == $id) {
        $rootNodesIDs []= $id;
        continue;
    }

    if (array_key_exists($parentId, $childrenReferences)) {
        $childrenReferences[$parentId] []= $id;         
    } else {
        $childrenReferences[$parentId] = array($id);
    }
}

function out_nodes($rootids) {
    global $childrenReferences, $xmlNodes;

    echo "<ul>";
    foreach ($rootids as $id) {
        $cat = $xmlNodes[$id];
        echo "<li>ID: " . $cat->getElementsByTagName('Id')->item(0)->nodeValue . "--Name: " . $cat->getElementsByTagName('Name')->item(0)->nodeValue;
        if (array_key_exists($id, $childrenReferences)) { // intermediate node
            out_nodes($childrenReferences[$id]);
        }
        echo "</li>";
    }
    echo "</ul>";
}

ob_start();
out_nodes($rootNodesIDs);
ob_end_flush();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM