shi*_*shu 2 json dictionary tcl
我被迫使用TCL做某些事情,我需要创建一个json字符串,如下所示:
{ "mainKey": "mainValue", "subKey": [{"key1":"value1"},{"key2":"value2"}]}
Run Code Online (Sandbox Code Playgroud)
所以我想这样做:
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]
Run Code Online (Sandbox Code Playgroud)
当我将此字典转换为json时,我得到:
{"mainKey":"mainValue", "subKey":{"key1 value1":{"key2":"value2"}}}
Run Code Online (Sandbox Code Playgroud)
而不是必需的:
{ "mainKey": "mainValue", "subKey": [{"key1":"value1"},{"key2":"value2"}]}
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
首先,您必须了解TCL是一种非常无类型的语言。TCL中的列表和字典到底是什么?
在Tcl中,列表是一个格式正确的字符串,其中列表的每个成员之间都用空格(空格,制表符或换行符)分隔,并且如果项目中包含的数据包含空格,则可以通过以下方式对它们进行转义:
使用反斜杠转义:
"this is a list\ of\ four\ items"
Run Code Online (Sandbox Code Playgroud)使用""分组:
{this is a "list of four items"}
Run Code Online (Sandbox Code Playgroud)使用{}分组:
{this is a {list of four items}}
Run Code Online (Sandbox Code Playgroud)请注意,在内部,将字符串解析为列表后,Tcl将使用其他内部数据结构来存储列表以提高速度。但是从语义上讲,它仍然是一个字符串。就像HTML是特殊格式的字符串或JSON是特殊格式的字符串一样,Tcl采取的态度是列表只不过是特殊格式的字符串。
那么,什么是字典?在Tcl字典中是具有偶数个元素的列表。而已。没什么特别的。因此,字典在语义上也是字符串(尽管如上所述,一旦tcl看到您将该字符串用作字典,它将把它编译为不同的数据结构以优化速度)。
再次注意tcl的核心理念:几乎所有数据结构(数组除外)都是字符串,碰巧以具有特殊含义的方式进行了格式化。
这就是为什么您不能将tcl数据结构自动转换为JSON的原因-如果您要求Tcl猜测数据结构是什么,那么最终编写该猜测函数的程序员希望得到它。在您的情况下,似乎默认情况下始终检测具有偶数个元素作为dict的列表。
有几种方法可以做到这一点。您当然可以使用自定义的专用于循环或函数将数据结构(同样,这只是一种特殊格式的字符串)转换为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"}
}
}
}
Run Code Online (Sandbox Code Playgroud)
(有关JSON解析的原始实现和讨论,请参见http://wiki.tcl.tk/JSON)
因为tcl永远无法正确猜出您的“字符串”是什么,所以我选择向函数提供格式字符串以正确解释tcl数据结构。例如,使用上面的函数来编译您的字典,您可以这样调用它:
compile_json {dict subKey list} finalDict
Run Code Online (Sandbox Code Playgroud)
我恳求tcllib维护者窃取我的代码,因为我仍然相信这是在tcl中处理JSON的正确方法,但到目前为止,它仍然不在tcllib中。
顺便说一句:我将上述代码许可为公共领域,您或任何人都可以要求其完整所有权。