[AMG]: [[jsonEncode]] converts from a tagged data format to JSON. **Types** The available type tags are: array : List of elements. object : Key-value dictionary of elements. string : Arbitrary string value. number : Integer and real numeric value. literal : false, null, or true. Array and object type composition is supported in two ways. If the type is array or object, each element is represented as a two-element list, being the type and the value. This gets quite cumbersome when the values all have uniform type, so the outer type may be a two-element list, the second of which is the type used for all values. More deeply nested data structures can be defined either by further nesting the second type element or by flattening the list. **Examples** ======none % jsonEncode string hello "hello" % jsonEncode number 42 42 % jsonEncode literal null null % jsonEncode array {{string hello} {number 42} {literal null}} ["hello",42,null] % jsonEncode object {foo {string hello} bar {number 42} quux {literal null}} {"foo":"hello","bar":42,"quux":null} % jsonEncode array {{array {{number 1} {number 2}}} {array {{number 3} {number 4}}}} [[1,2],[3,4]] % jsonEncode {array {array number}} {{1 2} {3 4}} [[1,2],[3,4]] % jsonEncode {array array number} {{1 2} {3 4}} [[1,2],[3,4]] % jsonEncode {array array string} {{1 2} {3 4}} [["1","2"],["3","4"]] % jsonEncode {object object string} {name {first Andy last Goth} contact {email andrew.m.goth@gmail.com telephone 555-1234}} {"name":{"first":"Andy","last":"Goth"},"contact":{"email":"andrew.m.goth@gmail.com","telephone":"555-1234"}} ====== **Implementation** ====== # jsonEncode -- # Encodes data in the JSON format per https://tools.ietf.org/html/rfc7159. proc jsonEncode {type data} { set comma {} if {[llength $type] == 1} { # One-element type. switch $type { array { # Recursively encode each array element. Elements are themselves # two-element lists consisting of type and value. append result \[ foreach element $data { append result $comma [jsonEncode {*}$element] set comma , } append result \] } object { # Recursively encode each object key and value. Keys are always # strings, and values are two-element lists consisting of type and # underlying data value. append result \{ foreach {key element} $data { append result $comma [jsonEncode string $key] :\ [jsonEncode {*}$element] set comma , } append result \} } string { # Encode the minimal set of required escape sequences. append result \" [string map { \x00 \\u0000 \x01 \\u0001 \x02 \\u0002 \x03 \\u0003 \x04 \\u0004 \x05 \\u0005 \x06 \\u0006 \x07 \\u0007 \x08 \\u0008 \x09 \\u0009 \x0a \\u000a \x0b \\u000b \x0c \\u000c \x0d \\u000d \x0e \\u000e \x0f \\u000f \x10 \\u0010 \x11 \\u0011 \x12 \\u0012 \x13 \\u0013 \x14 \\u0014 \x15 \\u0015 \x16 \\u0016 \x17 \\u0017 \x18 \\u0018 \x19 \\u0019 \x1a \\u001a \x1b \\u001b \x1c \\u001c \x1d \\u001d \x1e \\u001e \x1f \\u001f \\ \\\\ \" \\\" } $data] \" } number { # Potential improvement: check for valid numbers. append result $data } literal { # The only valid literals are false, null, and true. if {$data ni {false null true}} { error "invalid JSON literal \"$data\":\ must be false, null, or true" } append result $data }} } elseif {[llength $type] >= 2} { # Two-element type: first element is array or object, second element is # uniform type shared by all array or object values. # # Longer type: all elements are array or object, except final element # may be any supported type. if {[llength $type] == 2} { set subtype [lindex $type 1] } else { set subtype [lrange $type 1 end] } switch [lindex $type 0] { array { # Recursively encode each array element, using the shared subtype. append result \[ foreach element $data { append result $comma [jsonEncode $subtype $element] set comma , } append result \] } object { # Recursively encode each object value, using the shared subtype. append result \{ foreach {key value} $data { append result $comma [jsonEncode string $key] :\ [jsonEncode $subtype $value] set comma , } append result \} }} } # Confirm the type was recognized. if {![info exists result]} { error "invalid JSON type \"$type\": must be array, object, string, number, literal, or {array|object ?...? subtype} where subtype is recursively any valid JSON type" } # Return the encoded result. return $result } ====== **TODO** * [[jsonDecode]] * Unit tests <> Internet | JSON