dpnfxk251524 2014-10-20 00:16
浏览 29
已采纳

将多维JSON打印为html表单输入,名称为xpath属性

I am trying to print any JSON object as simple HTML form inputs with the name properties as the Xpath of the json property in dot notation.

So far it works but i loose track of the initial

    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);

PRINTS...

    <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='' />

PROBLEM BEING: I loose track of top level node names - "icon" in this case - as i traverse the array.

It should look like this:

    <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='' />

(i will accept answers in any language)

  • 写回答

1条回答 默认 最新

  • douyakan8924 2014-10-26 13:50
    关注

    This answer will be for PHP. As @Ghost had already commented and you confirmed, this needs to be solved with recursion. However, recursion can be somewhat cumbersome in your scenario.

    So what you can do in PHP is to turn the recursion into your flat list of input elements by collaborating with RecursiveIteratorIterator easily.

    Let's start with a first, simple example which still is incomplete but shows how it works. This and the following examples will make use of your JSON string, but I name the variables a little differently:

    $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);
    

    So the first example showing how to make use of RecursiveIteratorIterator here to turn your recursive tree structure you have in the JSON string into a flat list:

    $it   = new RecursiveArrayIterator($json);
    $rit  = new RecursiveIteratorIterator($it);
    foreach ($rit as $key => $value) {
        printf("%s: %s
    ", $key, var_export($value, 1));
    }
    

    This outputs all leaf-nodes of that tree with key and value one after the other:

    id: 12
    name: 'live music'
    url: NULL
    url: NULL
    url: NULL
    url: NULL
    display_name: NULL
    top_level: false
    

    It still does not have the path to each node what you're looking for as well. But it already shows, that the tree has been turned into a list.

    To now obtain the path to each node, RecursiveIteratorIterator allows to traverse all keys up to the current node's iterator through its getSubIterator method. Taking depth information into account, the path can be easily created:

    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
    ", $jsonPath, var_export($value, 1));
    }
    

    This now produces the following output:

    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
    

    which now shows, that obtaining the path to each node is easily possible. This still needs some fine-tuning as you actually don't want the key of the first (0) level. This can be done by initializing $level to 1 in the for loop:

        for ($level = 1; $level <= $rit->getDepth(); $level++) {
                      ^
    

    Updated output:

    id: 12
    name: 'live music'
    icon.url: NULL
    icon.thumb.url: NULL
    icon.ios_profile.url: NULL
    ...
    

    so this solves the underlying issue already but also allows you to care about the output later. Wrapping this up and exploiting __toString even allows you to easily create a HTML widget:

    /**
     * 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" />'."
    ",
                    htmlspecialchars($path), htmlspecialchars($value)
                );
            }
            return $html;
        }
    }
    

    This encapsulates or the needed processing logic in a simple call:

    echo new JsonForm($jsonStr);
    

    producing the following exemplary output:

    <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" />
    

    I hope this gives some pointers. It shows how you can treat the tree structure as a flat list thanks to the operation of RecursiveIteratorIterator in PHP (reference: How does RecursiveIteratorIterator work in PHP?).

    The building of the path in a recursive structure based on subkeys has been previously outlined in

    . Most likely there are more examples of this.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 目详情-五一模拟赛详情页
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line