我正在尝试将任何 JSON 对象打印为简单的 HTML 表单输入,并将名称属性作为点表示法中 json 属性的 Xpath。
到目前为止它是有效的,但我忘记了最初的
function printInp($title, $pre, $val, $rulekey = false) {
$html = "<label for='$pre'>$pre</label>";
$html .= "<input name='$pre' value='$val' type='text' />";
return $html;
}
function printForm($title, $item, $pre = '', $rulekey=false) {
if (!is_array($item)) {
echo printInp($title, $pre, $item, $rulekey);
} else {
foreach ($item as $key => $val) {
$pre = (empty($pre)) ? $key : $pre . '.' . $key;
if (is_array($val)) {
printForm($title, $val, $pre, $key);
} else {
echo printInp($title, $pre, $val, $key);
}
$pre = '';
}
}
}
$jsonStr = json_decode('[{"id":12,"name":"live music","icon":{"url":null,"thumb":{"url":null},"ios_profile":{"url":null},"medium":{"url":null}},"display_name":null,"top_level":false}]', TRUE);
echo printForm('test', $jsonStr);
打印...
<label for='id'>id</label><input name='id' value='12' type='text' class='' />
<label for='name'>name</label><input name='name' value='live music' type='text' class='' />
<label for='icon.url'>icon.url</label><input name='icon.url' value='' type='text' class='' />
<label for='thumb.url'>thumb.url</label><input name='thumb.url' value='' type='text' class='' />
<label for='ios_profile.url'>ios_profile.url</label><input name='ios_profile.url' value='' type='text' class='' />
<label for='medium.url'>medium.url</label><input name='medium.url' value='' type='text' class='' />
<label for='display_name'>display_name</label><input name='display_name' value='' type='text' class='' />
<label for='top_level'>top_level</label><input name='top_level' value='' type='text' class='' />
问题在于:当我遍历数组时,我失去了对顶级节点名称(在本例中为“图标”)的跟踪。
它应该是这样的:
<label for='id'>id</label><input name='id' value='12' type='text' class='' />
<label for='name'>name</label><input name='name' value='live music' type='text' class='' />
<label for='icon.url'>icon.url</label><input name='icon.url' value='' type='text' class='' />
<label for='icon.thumb.url'>icon.thumb.url</label><input name='icon.thumb.url' value='' type='text' class='' />
<label for='icon.ios_profile.url'>icon.ios_profile.url</label><input name='icon.ios_profile.url' value='' type='text' class='' />
<label for='icon.medium.url'>icon.medium.url</label><input name='icon.medium.url' value='' type='text' class='' />
<label for='display_name'>display_name</label><input name='display_name' value='' type='text' class='' />
<label for='top_level'>top_level</label><input name='top_level' value='' type='text' class='' />
(我会接受任何语言的回答)
最佳答案
这个答案将针对 PHP。正如@Ghost 已经评论过并且您确认的那样,这需要通过递归来解决。但是,递归在您的场景中可能有些麻烦。
因此,您可以在 PHP 中通过轻松地与 RecursiveIteratorIterator 协作,将递归转换为输入元素的平面列表。
让我们从第一个简单的例子开始,它仍然不完整,但展示了它是如何工作的。此示例和以下示例将使用您的 JSON 字符串,但我对变量的命名略有不同:
$jsonStr
= <<<JSON
[
{
"id" : 12,
"name": "live music",
"icon": {
"url" : null,
"thumb" : {"url": null},
"ios_profile": {"url": null},
"medium" : {"url": null}
},
"display_name": null,
"top_level" : false
}
]
JSON;
$json = json_decode($jsonStr, true);
所以第一个示例展示了如何在这里使用 RecursiveIteratorIterator 将 JSON 字符串中的递归树结构转换为平面列表:
$it = new RecursiveArrayIterator($json);
$rit = new RecursiveIteratorIterator($it);
foreach ($rit as $key => $value) {
printf("%s: %s\n", $key, var_export($value, 1));
}
这会输出该树的所有叶节点,键和值一个接一个地输出:
id: 12
name: 'live music'
url: NULL
url: NULL
url: NULL
url: NULL
display_name: NULL
top_level: false
它仍然没有您正在寻找的每个节点的路径。但它已经表明,树已变成列表。
现在要获取每个节点的路径,RecursiveIteratorIterator 允许通过其 getSubIterator
方法遍历所有键直到当前节点的迭代器。考虑到深度信息,可以轻松创建路径:
foreach ($rit as $key => $value) {
$jsonPathSegments = [];
for ($level = 0; $level <= $rit->getDepth(); $level++) {
$jsonPathSegments[$level] = $rit->getSubIterator($level)->key();
}
$jsonPath = implode('.', $jsonPathSegments);
printf("%s: %s\n", $jsonPath, var_export($value, 1));
}
现在产生以下输出:
0.id: 12
0.name: 'live music'
0.icon.url: NULL
0.icon.thumb.url: NULL
0.icon.ios_profile.url: NULL
0.icon.medium.url: NULL
0.display_name: NULL
0.top_level: false
现在表明,很容易获得到每个节点的路径。这仍然需要一些微调,因为您实际上不需要第一 (0) 级的 key 。这可以通过在 for
循环中将 $level
初始化为 1
来完成:
for ($level = 1; $level <= $rit->getDepth(); $level++) {
^
更新后的输出:
id: 12
name: 'live music'
icon.url: NULL
icon.thumb.url: NULL
icon.ios_profile.url: NULL
...
所以这解决了潜在的问题,但也允许您稍后关心输出。总结并利用 __toString
甚至可以让您轻松创建 HTML 小部件:
/**
* Class JsonForm
*
* Exemplary HTML Widget
*/
class JsonForm extends RecursiveIteratorIterator
{
private $json;
public function __construct($json) {
if (is_string($json) || is_object($json) && method_exists($json, '__toString')) {
$json = json_decode($json);
}
parent::__construct(new RecursiveArrayIterator($json));
}
public function getJsonPath() {
$jsonPathSegments = [];
for ($level = 1; $level <= $this->getDepth(); $level++) {
$jsonPathSegments[$level] = $this->getSubIterator($level)->key();
}
$jsonPath = implode('.', $jsonPathSegments);
return $jsonPath;
}
public function __toString() {
$html = '';
foreach ($this as $value) {
$path = $this->getJsonPath();
$html .= sprintf(
'<label for="%1$s">%1$s</label><input name="%1$s" value="%2$s" type="text" />'."\n",
htmlspecialchars($path), htmlspecialchars($value)
);
}
return $html;
}
}
这将所需的处理逻辑封装在一个简单的调用中:
echo new JsonForm($jsonStr);
生成以下示例输出:
<label for="id">id</label><input name="id" value="12" type="text" />
<label for="name">name</label><input name="name" value="live music" type="text" />
<label for="icon.url">icon.url</label><input name="icon.url" value="" type="text" />
<label for="icon.thumb.url">icon.thumb.url</label><input name="icon.thumb.url" value="" type="text" />
<label for="icon.ios_profile.url">icon.ios_profile.url</label><input name="icon.ios_profile.url" value="" type="text" />
<label for="icon.medium.url">icon.medium.url</label><input name="icon.medium.url" value="" type="text" />
<label for="display_name">display_name</label><input name="display_name" value="" type="text" />
<label for="top_level">top_level</label><input name="top_level" value="" type="text" />
希望能给大家一些指点。它显示了如何通过 PHP 中的 RecursiveIteratorIterator 操作将树结构视为平面列表(引用:How does RecursiveIteratorIterator work in PHP?)。
之前在
中概述了基于子 key 的递归结构中路径的构建- PHP - Return array of parents from multidimensional associative array for breadcrumb list (Dec 2012) ,
- get all array keys by value (Feb 2013) 或
- Get array's key recursively and create underscore seperated string (May 2010)
.很可能还有更多这样的例子。
关于javascript - 将多维 JSON 打印为 html 表单输入,名称为属性的 xpath,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26456871/