Version 22 of build JSON with tdom

Updated 2022-07-03 16:50:49 by rattleCAD
Whatbuild JSON with tdom using createNodeCmd
Requirestdom 0.9.2
tagstdom
referencehttp://www.tdom.org/index.html/doc/trunk/doc/index.html
Updated03.07.2022

Index

  1. Challenge
  2. insufficient Approach
  3. Issues and Improvements
  4. improved Approvements
  5. Summary

Challenge

how to build a JSON like this:

{
    "aNumber": 0.123,
    "aNumberAsString": "0.123",
    "aString": "this is a String",
    "a key with spaces": "please take care on setting: dom setNameCheck 0",
    "aArray": ["a","b","c"],   
    "aObject": {
        "foo":"that",
        "bar":"grill"
    },
    "aObjectArray": [
        {
            "foo": "objArray_01_foo",
            "bar": "objArray_01_bar",
            "array": ["five_01_a", "five_01_b", "five_01_c"]
        },
        {
            "foo": "objArray_02_foo",
            "bar": "objArray_02_bar",
            "array": ["five_02_a", "five_02_b", "five_02_c"]
        }
    ] 
}

insufficient Approach

    #
    # --- load tdom ---
    #
package require tdom 0.9    ;# current version: 0.9.2 (May, 2022)
puts "tdom: [package versions tdom]"
    #
    # http://www.tdom.org/index.html/file?name=tests/domjson.test&ci=release
    #
    #
set doc [dom createDocumentNode root]
    #
puts "asXML:  [$root asXML  -indent 4]"
puts "asJSON: [$root asJSON -indent 4]"
    #
    # -- aNumber --
    #
set node_Number     [$doc createElement "aNumber" NONE]
$node_Number appendChild [$doc createTextNode 0.123 NUMBER]
$root appendChild $node_Number
    #
    # -- aNumberAsString --
    #
set node_StringNum  [$doc createElement "aNumberAsString" NONE]
$node_StringNum appendChild [$doc createTextNode 0.123 NUMBER]
$root appendChild $node_StringNum
    #
    # -- aString --
    #
set node_String     [$doc createElement "aNumberString" NONE]
$node_String appendChild [$doc createTextNode "0.123" NUMBER]
$root appendChild $node_String
    #
set node_String     [$doc createElement "aString" NONE]
$node_String appendChild [$doc createTextNode "this is a String" STRING]
$root appendChild $node_String
    #
    # -- a key with spaces --
    #
    # ... you have to disable namecheck first
dom setNameCheck 0
set node_String     [$doc createElement "a key with spaces" NONE]
    # [dom setNameCheck] == 1  ... brings this error
    #       ERROR: Invalid tag name 'a key with spaces'
    #         while executing
    #       "$doc createElement "a key with spaces" NONE"
    #         invoked from within
    #       "set  node_String     [$doc createElement "a key with spaces" NONE]"
    #
$node_String appendChild [$doc createTextNode "please take care on setting: dom setNameCheck 0" STRING]
$root appendChild $node_String
    #
    # -- aArray --
    #
set node_Array      [$doc createElement "aArray" ARRAY]
$node_Array appendChild [$doc createTextNode "a" STRING]
$node_Array appendChild [$doc createTextNode "b" STRING]
$node_Array appendChild [$doc createTextNode "c" STRING]
$root appendChild $node_Array
    #
    #
    # -- aObject --
    #
set node_Object     [$doc createElement "aObject" OBJECT]
    #
set node__Label     [$doc createElement "foo" NONE]
set node__Value     [$doc createTextNode "that" STRING]
$node_Object appendChild $node__Label
$node__Label appendChild $node__Value
    #
set node__Label     [$doc createElement "bar" NONE]
set node__Value     [$doc createTextNode "grill" STRING]
$node_Object appendChild $node__Label
$node__Label appendChild $node__Value
    #
$root appendChild $node_Object
    #
    #
    # -- aObjectArray --
    #
set node_ObjArray   [$doc createElement "aObjectArray"]
    #
set node__Obj_01    [$doc createElement "obj0001"]
    #
set node__Label     [$doc createElement "foo"]
set node__Value     [$doc createTextNode "objArray_01_foo" STRING]
$node__Label  appendChild $node__Value
$node__Obj_01 appendChild $node__Label
set node__Label     [$doc createElement "bar"]
set node__Value     [$doc createTextNode "objArray_01_bar" STRING]
$node__Label  appendChild $node__Value
$node__Obj_01 appendChild $node__Label
    #
set node__Array     [$doc createElement "array" ARRAY]
$node__Array appendChild [$doc createTextNode "five_01_a" STRING]
$node__Array appendChild [$doc createTextNode "five_01_b" STRING]
$node__Array appendChild [$doc createTextNode "five_01_c" STRING]
    #
$node__Obj_01 appendChild $node__Array   
    #
    #
set node__Obj_02    [$doc createElement "obj0002"]
    #
set node__Label     [$doc createElement "foo"]
set node__Value     [$doc createTextNode "objArray_02_foo" STRING]
$node__Label  appendChild $node__Value
$node__Obj_02 appendChild $node__Label
set node__Label     [$doc createElement "bar"]
set node__Value     [$doc createTextNode "objArray_02_bar" STRING]
$node__Label  appendChild $node__Value
$node__Obj_02 appendChild $node__Label
    #
set node__Array     [$doc createElement "array" ARRAY]
$node__Array appendChild [$doc createTextNode "five_02_a" STRING]
$node__Array appendChild [$doc createTextNode "five_02_b" STRING]
$node__Array appendChild [$doc createTextNode "five_02_c" STRING]
    #
$node__Obj_02 appendChild $node__Array
    #
$node_ObjArray appendChild $node__Obj_01
$node_ObjArray appendChild $node__Obj_02
    #
    #
$root appendChild $node_ObjArray
    #
    # in the case of mixed OBJECT and ARRAYs you have to update the specific rendering
$node_ObjArray jsonType ARRAY    
$node__Obj_01  jsonType OBJECT   
$node__Obj_02  jsonType OBJECT   
    #
puts "== \$resultJSON ===="
puts [$doc asXML  -indent 4]
puts "== \$resultJSON ===="
puts [$doc asJSON -indent 4]
    #

... output of this script:

tdom: 0.9.2
asXML:
asJSON: {}
== $resultJSON ====
<aNumber>0.123</aNumber>
<aNumberAsString>0.123</aNumberAsString>
<aNumberString>0.123</aNumberString>
<aString>this is a String</aString>
<a key with spaces>please take care on setting: dom setNameCheck 0</a key with spaces>
<aArray>abc</aArray>
<aObject>
    <foo>that</foo>
    <bar>grill</bar>
</aObject>
<aObjectArray>
    <obj0001>
        <foo>objArray_01_foo</foo>
        <bar>objArray_01_bar</bar>
        <array>five_01_afive_01_bfive_01_c</array>
    </obj0001>
    <obj0002>
        <foo>objArray_02_foo</foo>
        <bar>objArray_02_bar</bar>
        <array>five_02_afive_02_bfive_02_c</array>
    </obj0002>
</aObjectArray>

== $resultJSON ====
{
    "aNumber": "0.123",
    "aNumberAsString": "0.123",
    "aNumberString": "0.123",
    "aString": "this is a String",
    "a key with spaces": "please take care on setting: dom setNameCheck 0",
    "aArray": [
        "a",
        "b",
        "c"
    ],
    "aObject": {
        "foo": "that",
        "bar": "grill"
    },
    "aObjectArray": [
        {
            "foo": "objArray_01_foo",
            "bar": "objArray_01_bar",
            "array": [
                "five_01_a",
                "five_01_b",
                "five_01_c"
            ]
        },
        {
            "foo": "objArray_02_foo",
            "bar": "objArray_02_bar",
            "array": [
                "five_02_a",
                "five_02_b",
                "five_02_c"
            ]
        }
    ]
}

Issues and Imoprovements

wrong Value

this Result: "aNumber": "0.123"
expected Result: "aNumber": 0.123

complex code

... the given approach takes a lot of lines to create this result

improved Approach

use

dom createNodeCmd 

to improve our code

    #
    # --- load tdom ---
    #
package require tdom 0.9    ;# current version: 0.9.2 (May, 2022)
puts "tdom: [package versions tdom]"
    #
    # http://www.tdom.org/index.html/file?name=tests/domjson.test&ci=release
    #
    #    
    #
puts "== 01 == \$resultJSON ===="
set doc [dom createDocumentNode root]
    #
puts "asXML:  [$root asXML  -indent 4]"
puts "asJSON: [$root asJSON -indent 4]"
    #
    #
    # our targetJSON includes nodes with predefined names: 
    #       "aNumber" "aString" "a key with spaces" "foo" "bar"
    #
    #   ... lets predefine dom-commands to create these nodes
    #
dom createNodeCmd -jsonType NONE    elementNode aNumber
dom createNodeCmd -jsonType NONE    elementNode aNumberAsString
dom createNodeCmd -jsonType NONE    elementNode aString
dom createNodeCmd -jsonType NONE    elementNode "a key with spaces"
dom createNodeCmd -jsonType NONE    elementNode foo
dom createNodeCmd -jsonType NONE    elementNode bar
dom createNodeCmd -jsonType NONE    elementNode array
dom createNodeCmd -jsonType ARRAY   elementNode "aArray"
dom createNodeCmd -jsonType OBJECT  elementNode "aObject"
dom createNodeCmd -jsonType ARRAY   elementNode "aObjectArray"
    #
    # ... json distinguishs between 
    #     ... Arrays  ["A","B","C"] and 
    #     ... Objects {"a": "A", "b": "B", "c":"C"}
    #
dom createNodeCmd -jsonType NUMBER  textNode    jsonNumber
dom createNodeCmd -jsonType STRING  textNode    jsonString    
    #
    #
set resultJSON [dom createDocumentNode]
    #
puts "== 02 == \$resultJSON ===="
puts [$resultJSON asJSON -indent 4]    
    #
$resultJSON appendFromScript {
    aNumber {jsonNumber 0.123}
    aNumberAsString {jsonString 0.123}
    aString {jsonString "this is a string"}
    "a key with spaces" {jsonString "It's possible."}
    aArray {
        jsonString a
        jsonString b
        jsonString c
    }
    aObject {
        foo {jsonString "that"}
        bar {jsonString "grill"}
    }
    aObjectArray {
        aObject {
            foo {jsonString "objArray_01_foo"}
            bar {jsonString "objArray_01_bar"}
            aArray {
                jsonString "five_01_a"
                jsonString "five_01_b"
                jsonString "five_01_c"
            }
        }
        aObject {
            foo {jsonString "objArray_02_foo"}
            bar {jsonString "objArray_02_bar"}
            aArray {
                jsonString "five_02_a"
                jsonString "five_02_b"
                jsonString "five_02_c"
            }
        }
    }
}
    #
    #
puts "== 03 == \$resultJSON ===="
puts [$resultJSON asXML  -indent 4]
puts "== 03 == \$resultJSON == final =="
puts [$resultJSON asJSON -indent 4]    
    #

... output of this script:

tdom: 0.9.2
== 01 == $resultJSON ====
asXML:
asJSON: {}
== 02 == $resultJSON ====
{}
== 03 == $resultJSON ====
<aNumber>0.123</aNumber>
<aNumberAsString>0.123</aNumberAsString>
<aString>this is a string</aString>
<a key with spaces>It's possible.</a key with spaces>
<aArray>abc</aArray>
<aObject>
    <foo>that</foo>
    <bar>grill</bar>
</aObject>
<aObjectArray>
    <aObject>
        <foo>objArray_01_foo</foo>
        <bar>objArray_01_bar</bar>
        <aArray>five_01_afive_01_bfive_01_c</aArray>
    </aObject>
    <aObject>
        <foo>objArray_02_foo</foo>
        <bar>objArray_02_bar</bar>
        <aArray>five_02_afive_02_bfive_02_c</aArray>
    </aObject>
</aObjectArray>

== 03 == $resultJSON == final ==
{
    "aNumber": 0.123,
    "aNumberAsString": "0.123",
    "aString": "this is a string",
    "a key with spaces": "It's possible.",
    "aArray": [
        "a",
        "b",
        "c"
    ],
    "aObject": {
        "foo": "that",
        "bar": "grill"
    },
    "aObjectArray": [
        {
            "foo": "objArray_01_foo",
            "bar": "objArray_01_bar",
            "aArray": [
                "five_01_a",
                "five_01_b",
                "five_01_c"
            ]
        },
        {
            "foo": "objArray_02_foo",
            "bar": "objArray_02_bar",
            "aArray": [
                "five_02_a",
                "five_02_b",
                "five_02_c"
            ]
        }
    ]
}

Summary

  • enable creating a node as a number
  • createNodeCmd:
    • define nodes with name and type
    • create your JSON like it should look like at the end