我想从一个平面结构创建一个JSON树,在本例中是一个App.net线程。
我想要像这样的JSON
"id": "12345",
"name": "Ringo",
"data":
{
"avatar": "",
"text": "We All Live",
},
"children": [{
"id": "34567",
"name": "John",
"data":
{
"avatar": "",
"text": "In a pink submarine?",
},
"children": [{
"id": "35555",
"name": "George",
"data":
{
"avatar": "",
"text": "Don't be daft",
},
"children": []
}]
},{
"id": "98765",
"name": "Paul",
"data":
{
"avatar": "",
"text": "In a yellow submarine?",
},
"children": []
}]
因此,每个帖子可以有多个子帖子。每个孩子都可以有孩子。
从App.net返回的JSON是而不是线程化的。
{
"id": "98765",
"parent": "12345"
"details": {
...}
},
{
"id": "34567",
"parent": "12345"
"details": {
...}
},
我已经使用json_decode()将json响应获取到一个数组中。我可以使用foreach进行迭代。
如何将每个帖子放在多维数组的正确部分?
Parent
|_
|-child
|-child
| |-child
|-child
etc
我会使用引用,这是PHP中经常被遗忘的硬链接。类似这样的东西:
我假设您有一个从App.net API调用返回的$posts
数组。
(未经测试,可能无法编译/运行/可能有错误/可能是更有效的方法)
// first throw everything into an associative array for easy access
$references = array();
foreach ($posts as $post) {
$id = $post['id'];
$post['children'] = array();
$references[$id] = $post;
}
// now create the tree
$tree = array();
foreach ($references as &$post) {
$id = $post['id'];
$parentId = $post['parent'];
// if it's a top level object, add it to the tree
if (!$parentId) {
$tree[] =& $references[$id];
}
// else add it to the parent
else {
$references[$parentId]['children'][] =& $post;
}
// avoid bad things by clearing the reference
unset($post);
}
// encode it
print json_encode($tree);
只是在这里勾勒出一个答案:所有假设都可以将所有条目保存在RAM中,否则您将不得不做出一些排序假设,并在完成完整单元后清除我们的数组。
创建一个数组posts
,该数组由包含详细信息和子数组的id保持结构索引。然后迭代您的输入数组,并针对每个元素:
- 如果尚未创建
posts[id]
- 填写
post[id]
的详细信息 - 如果有父级,则查找(如果需要,则创建它——不知道排序如何)
posts[parent_id]
,并将此结构添加到那里的子级
最后,您可以迭代所有帖子,而那些没有父级的帖子是正确填写了其子级的根。
我编写了一个类和示例脚本来实现我认为您想要的。
它将平面结构转换为层次结构,还考虑到孤立更新(没有可用父更新的更新)。
Update.php
<?php
/**
* An App.net update.
*/
class Update extends ArrayObject
{
/**
* The update's children.
*
* @var array
*/
private $children = array();
/**
* The parent update.
*
* @var Update
*/
private $parent;
/**
* Adds a child to this update.
*
* @param Update The child update.
*/
public function addChild(self $child)
{
$child->setParent($this);
$this->children[] = $child;
}
/**
* Sets the parent update.
*
* @param Update The parent update.
*/
public function setParent(self $parent = null)
{
$this->parent = $parent;
}
/**
* Converts the update and its children to JSON.
*
* @param boolean $encode Automatically encode?
*
* @return string The JSON-encoded update.
*/
public function toJson($encode = true)
{
$data = $this->getArrayCopy();
if ($this->children) {
$data['children'] = array();
foreach ($this->children as $child) {
$data['children'][] = $child->toJSON(false);
}
}
if ($encode) {
return json_encode($data);
}
return $data;
}
}
build.php
<?php
require 'Update.php';
$updates = <<<UPDATES
[
{
"id": "12345",
"name": "Ringo",
"data": {
"avatar": "",
"text": "We All Live"
}
},
{
"id": "34567",
"parent": "12345",
"name": "John",
"data": {
"avatar": "",
"text": "In a pink submarine?"
}
},
{
"id": "98765",
"parent": "12345",
"name": "Paul",
"data": {
"avatar": "",
"text": "In a yellow submarine?"
}
}
]
UPDATES;
$original = json_decode($updates, true);
$parents = array();
$children = array();
foreach ($original as $update) {
if (empty($update['parent'])) {
$parents[$update['id']] = $parent = new Update($update);
if (isset($children[$update['id']])) {
foreach ($children[$update['id']] as $child) {
$parent->addChild($child);
}
unset($children[$update['id']]);
}
} else {
$child = new Update($update);
if (isset($parents[$update['parent']])) {
$parents[$update['parent']]->addChild($child);
} else {
if (false === isset($children[$update['parent']])) {
$children[$update['parent']] = array();
}
$children[$update['parent']][] = $child;
}
}
}
// Anything in children at this point are orphans
echo "Parents:'n";
foreach ($parents as $parent) {
echo $parent->toJson();
}
echo "'n'nOrphans:'n";
foreach ($children as $parent => $orphans) {
foreach ($orphans as $orphan) {
echo $orphan->toJson();
}
}