Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Json 在TCL中的dict中创建dict列表_Json_Dictionary_Tcl - Fatal编程技术网

Json 在TCL中的dict中创建dict列表

Json 在TCL中的dict中创建dict列表,json,dictionary,tcl,Json,Dictionary,Tcl,我被迫使用TCL来做一些事情,我需要创建一个json字符串,如下所示: { "mainKey": "mainValue", "subKey": [{"key1":"value1"},{"key2":"value2"}]} compile_json {dict subKey list} finalDict 所以我试着这样做: set subDict1 [dict create key1 value1] set subDict2 [dict create key2 value2] set sub

我被迫使用TCL来做一些事情,我需要创建一个json字符串,如下所示:

{ "mainKey": "mainValue", "subKey": [{"key1":"value1"},{"key2":"value2"}]}
compile_json {dict subKey list} finalDict
所以我试着这样做:

set subDict1 [dict create key1 value1]
set subDict2 [dict create key2 value2]
set subDictList [list $subDict1 $subDict2]
set finalDict [dict create mainKey mainValue subKey $subDictList]
当我将此dict转换为json时,我得到:

{"mainKey":"mainValue", "subKey":{"key1 value1":{"key2":"value2"}}} 
而不是要求:

{ "mainKey": "mainValue", "subKey": [{"key1":"value1"},{"key2":"value2"}]}

我做错了什么?

首先,您必须了解TCL是一种非常无类型的语言。tcl中的列表和目录到底是什么

在Tcl中,列表是一个格式正确的字符串,其中列表的每个成员由空格(空格、制表符或换行符)分隔,如果项目包含的数据包含空格,则可以通过以下方式进行转义:

  • 使用反斜杠转义:

    "this is a list\ of\ four\ items"
    
  • 使用
    分组:

    {this is a "list of four items"}
    
    {this is a {list of four items}}
    
  • 使用
    {}
    分组:

    {this is a "list of four items"}
    
    {this is a {list of four items}}
    
  • 请注意,在内部,一旦字符串被解析为列表,Tcl将使用不同的内部数据结构来存储该列表以提高速度。但在语义上它仍然是一个字符串。就像HTML是一个特殊格式的字符串或JSON是一个特殊格式的字符串一样,Tcl采取的态度是列表只是特殊格式的字符串

    那么,什么是口述?在Tcl中,dict是具有偶数个元素的列表。就这样。没什么特别的。因此,dict在语义上也是一个字符串(尽管如上所述,一旦tcl看到您将该字符串用作dict,它会将其编译为不同的数据结构以优化速度)

    请再次注意tcl的核心理念:几乎所有的数据结构(数组除外)都仅仅是字符串,其格式恰好具有特殊意义

    这就是您无法将tcl数据结构自动转换为JSON的原因——如果您让tcl猜测数据结构是什么,那么您最终会得到编写猜测函数的程序员想要的结果。在您的例子中,它看起来默认总是检测元素数为偶数的列表

    那么,如何正确地生成JSON呢? 有几种方法可以做到这一点。当然,您可以使用定制的专用循环或函数将数据结构(同样,它只是一个特殊格式的字符串)转换为JSON

    几年前,我编写了这个JSON编译器:

    # data is plain old tcl values
    # spec is defined as follows:
    # {string} - data is simply a string, "quote" it if it's not a number
    # {list} - data is a tcl list of strings, convert to JSON arrays
    # {list list} - data is a tcl list of lists
    # {list dict} - data is a tcl list of dicts
    # {dict} - data is a tcl dict of strings
    # {dict xx list} - data is a tcl dict where the value of key xx is a tcl list
    # {dict * list} - data is a tcl dict of lists
    # etc..
    proc compile_json {spec data} {
        while [llength $spec] {
            set type [lindex $spec 0]
            set spec [lrange $spec 1 end]
    
            switch -- $type {
                dict {
                    lappend spec * string
    
                    set json {}
                    foreach {key val} $data {
                        foreach {keymatch valtype} $spec {
                            if {[string match $keymatch $key]} {
                                lappend json [subst {"$key":[
                                    compile_json $valtype $val]}]
                                break
                            }
                        }
                    }
                    return "{[join $json ,]}"
                }
                list {
                    if {![llength $spec]} {
                        set spec string
                    } else {
                        set spec [lindex $spec 0]
                    }
                    set json {}
                    foreach {val} $data {
                        lappend json [compile_json $spec $val]
                    }
                    return "\[[join $json ,]\]"
                }
                string {
                    if {[string is double -strict $data]} {
                        return $data
                    } else {
                        return "\"$data\""
                    }
                }
                default {error "Invalid type"}
            }
        }
    }
    
    (有关JSON解析的原始实现和讨论,请参见)

    因为tcl永远无法正确猜测“字符串”是什么,所以我选择向函数提供格式字符串,以便正确解释tcl数据结构。例如,使用上面的函数编译dict,您可以这样调用它:

    { "mainKey": "mainValue", "subKey": [{"key1":"value1"},{"key2":"value2"}]}
    
    compile_json {dict subKey list} finalDict
    
    我恳求tcllib维护人员窃取我的代码,因为我仍然相信这是在tcl中处理JSON的正确方法,但到目前为止,它仍然不在tcllib中


    顺便说一句:我将上面的代码授权为公共域,如果您愿意,您或任何人都可以声称它是完全的作者。

    说Tcl是一种无类型语言并不是完全错误的,因为Tcl程序中的数据对象类型在代码中没有完全表达出来,甚至在内部表示数据对象的
    Tcl_Obj
    结构中也不总是这样。尽管如此,类型在Tcl程序中并不是不存在的,只是类型系统在Tcl中的侵入性比在大多数其他编程语言中要小得多

    Tcl程序中完整的类型定义来自程序执行时代码和数据对象的动态组合。解释器信任您告诉它您希望数据对象的行为

    作为一个例子,考虑下面的字符串:

    set s {title: Mr. name: Peter surname: Lewerin}
    
    这是字符串、数组还是字典?事实上,所有这些。(至少它不是整数、双精度或布尔值以及其他可能的Tcl类型。)

    使用此字符串,我可以回答许多问题:

    告诉我你的名字

    有礼貌的人怎么称呼你

    你的姓是什么

    在这里,我使用相同的字符串作为字符串、字典和数组。所有三种类型的对象都使用了相同的字符串表示,正是我对其使用的操作决定了当时对象的类型

    类似地,文本
    1
    可以表示整数1、单个字符串1或布尔真值。没有办法指定你指的是哪种类型的1,但也没有必要,因为口译员不会抱怨歧义

    因为Tcl不存储完整的类型信息,所以很难序列化任意数据对象集合。但这并不意味着Tcl不能很好地处理序列化:您只需要向数据中添加注释

    此字符串:

    di [dm [st mainKey] [st mainValue]] [dm [st subKey] [ar [di [dm [st key1] [st value1]]] [di [dm [st key2] [st value2]]]]]
    
    可以输入Tcl解释器,并给出
    di
    dm
    st
    ar
    (我打算分别表示“dictionary”、“dictionary member”、“string”和“array”)的正确定义,我可以让字符串构造一个与问题中的字典结构等效的字典结构,或者是这样一个对象的字符串表示,仅仅是一个简单的键和值列表,或者XML,或者JSON,等等。通过使用名称空间和/或从解释器,我甚至可以在各种形式之间动态切换。我不会提供所有表单的示例,只提供JSON:

    proc di args {return "{[join $args {, }]}"}
    proc st val {return "\"$val\""}
    proc ar args {return "\[[join $args {, }]]"}
    proc dm {k v} {return "$k: $v"}
    
    输出变为:

    {"mainKey": "mainValue", "subKey": [{"key1": "value1"}, {"key2": "value2"}]}
    
    本例使用Tcl解释器的命令嵌套来定义数据的结构。Tcl甚至不需要这样做:一个令牌类和令牌列表(如扫描器将发出的令牌)就足够了:

    < : ' mainKey ' mainValue : ' subKey ( < : ' key1 ' value1 > < : ' key2 ' value2 > ) >
    
    另一种方法是创建常规的Tcl结构,并根据类型规范将其转换(“编译”)为压缩数据:

    set subDict1 [dict create key1 value1]
    set subDict2 [dict create key2 value2]
    set subDictList [list $subDict1 $subDict2]
    set finalDict [dict create mainKey mainValue subKey $subDictList]
    huddle compile {dict mainKey string subKey {list {dict * string}}} $finalDict
    
    最后一个命令的结果与上一个示例中最后一个
    huddle create
    命令的结果相同


    文档:,,,,,,

    您使用什么命令从
    finalDict
    创建JSON字符串?我使用的是JSON包。set myJson[::json::dict2json$finalDict]感谢您的深入了解。我也在怀疑同样的事情。但问题是怎么做
    package require huddle
    # -> 0.1.5
    set subDict1 [huddle create key1 value1]
    # -> HUDDLE {D {key1 {s value1}}}
    set subDict2 [huddle create key2 value2]
    # -> HUDDLE {D {key2 {s value2}}}
    set subDictList [huddle list $subDict1 $subDict2]
    # -> HUDDLE {L {{D {key1 {s value1}}} {D {key2 {s value2}}}}}
    set finalDict [huddle create mainKey mainValue subKey $subDictList]
    # -> HUDDLE {D {mainKey {s mainValue} subKey {L {{D {key1 {s value1}}} {D {key2 {s value2}}}}}}}
    huddle jsondump $finalDict {} {}
    # -> {"mainKey":"mainValue","subKey":[{"key1":"value1"},{"key2":"value2"}]}
    
    set subDict1 [dict create key1 value1]
    set subDict2 [dict create key2 value2]
    set subDictList [list $subDict1 $subDict2]
    set finalDict [dict create mainKey mainValue subKey $subDictList]
    huddle compile {dict mainKey string subKey {list {dict * string}}} $finalDict