tDOM

Check-in [8a8dee52e5]
Login

Check-in [8a8dee52e5]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added the "virtual" JSON type BOOLEAN for text nodes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8a8dee52e5eb58d4393d4d6d87a9d53759360ad9618d974ef974f4dcc8577865
User & Date: rolf 2025-01-22 22:30:18
Context
2025-01-22
22:31
Typo fix. check-in: 29b977cadc user: rolf tags: trunk
22:30
Added the "virtual" JSON type BOOLEAN for text nodes. check-in: 8a8dee52e5 user: rolf tags: trunk
22:25
Merged from trunk. Closed-Leaf check-in: 5768bc4e95 user: rolf tags: jsonbool
22:04
Added a few tests. check-in: 87ad52127a user: rolf tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to CHANGES.







1
2
3
4
5
6
7








2025-01-15  Rolf Ade  <[email protected]>

        Added the flag -notempty to dom createNodeCmd. If this flag is
        used the element will only appear in the tree if it is not
        empty. 

>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14

2025-01-22  Rolf Ade  <[email protected]>

        Added the "virtual" JSON type BOOLEAN for text nodes. If the
        text node value is a boolean in the sense of Tcl then the node
        serialize to the approprate JSON type. Otherwise it will be a
        JSON string.

2025-01-15  Rolf Ade  <[email protected]>

        Added the flag -notempty to dom createNodeCmd. If this flag is
        used the element will only appear in the tree if it is not
        empty. 

Changes to doc/dom.xml.
498
499
500
501
502
503
504






505
506
507
508
509
510
511
<syntax>
<cmd>textNodeCmd</cmd> ?-disableOutputEscaping? <m>?data?</m>
</syntax>

<p>If the json type of the created text node is NULL, TRUE or FALSE
then the <m>data</m> argument is optional, otherwise it this argument
must be given.</p>







<p>If the optional flag <m>-disableOutputEscaping</m> is given, the
escaping of the ampersand character (&amp;) and the left angle bracket (&lt;)
inside the data is disabled. You should use this flag carefully.</p>

<p>If the first argument of the method is <m>commentNode</m> or 
<m>cdataNode</m> the command will create an comment node or CDATA section 







>
>
>
>
>
>







498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
<syntax>
<cmd>textNodeCmd</cmd> ?-disableOutputEscaping? <m>?data?</m>
</syntax>

<p>If the json type of the created text node is NULL, TRUE or FALSE
then the <m>data</m> argument is optional, otherwise it this argument
must be given.</p>

<p>If the json type of the created text node is the virtual type
BOOLEAN then if the text value is a boolean as recognized by
Tcl_GetBooleanFromObj() the json value will according and if the text
node value is not a boolean value understood by Tcl the value will be
writen as json string.</p>

<p>If the optional flag <m>-disableOutputEscaping</m> is given, the
escaping of the ampersand character (&amp;) and the left angle bracket (&lt;)
inside the data is disabled. You should use this flag carefully.</p>

<p>If the first argument of the method is <m>commentNode</m> or 
<m>cdataNode</m> the command will create an comment node or CDATA section 
Changes to generic/domjson.h.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#define JSON_ARRAY 1
#define JSON_OBJECT 2
#define JSON_NULL 3
#define JSON_TRUE 4
#define JSON_FALSE 5
#define JSON_STRING 6
#define JSON_NUMBER 7


domDocument *
JSON_Parse (
    char *json,    /* Complete text of the json string being parsed */
    char *documentElement, /* name of the root element, may be NULL */
    int   maxnesting,
    char **errStr,







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#define JSON_ARRAY 1
#define JSON_OBJECT 2
#define JSON_NULL 3
#define JSON_TRUE 4
#define JSON_FALSE 5
#define JSON_STRING 6
#define JSON_NUMBER 7
#define JSON_BOOLEAN 8

domDocument *
JSON_Parse (
    char *json,    /* Complete text of the json string being parsed */
    char *documentElement, /* name of the root element, may be NULL */
    int   maxnesting,
    char **errStr,
Changes to generic/nodecmd.c.
628
629
630
631
632
633
634
635

636
637
638
639
640
641
642
        "NONE",
        "ARRAY",
        "OBJECT",
        "NULL",
        "TRUE",
        "FALSE",
        "STRING",
        "NUMBER"

    };

    if (objc < 3 ) {
        goto usage;
    }

    while (objc > 3) {







|
>







628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
        "NONE",
        "ARRAY",
        "OBJECT",
        "NULL",
        "TRUE",
        "FALSE",
        "STRING",
        "NUMBER",
        "BOOLEAN"
    };

    if (objc < 3 ) {
        goto usage;
    }

    while (objc > 3) {
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
            } else {
                type = TEXT_NODE;
            }
        } else {
            if (jsonType < 3 && jsonType > 0) {
                Tcl_SetResult(interp, "For a text node the jsonType "
                              "argument must be one out of this list: "
                              "TRUE FALSE NULL NUMBER STRING NONE",
                              NULL);
                return TCL_ERROR;
            }
            type = TEXT_NODE;
        }
        break;
    case CDS_NODE: 







|







752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
            } else {
                type = TEXT_NODE;
            }
        } else {
            if (jsonType < 3 && jsonType > 0) {
                Tcl_SetResult(interp, "For a text node the jsonType "
                              "argument must be one out of this list: "
                              "TRUE FALSE NULL NUMBER STRING NONE or BOOLEAN",
                              NULL);
                return TCL_ERROR;
            }
            type = TEXT_NODE;
        }
        break;
    case CDS_NODE: 
Changes to generic/tcldom.c.
199
200
201
202
203
204
205

206
207
208
209
210
211
212
    "ARRAY",
    "OBJECT",
    "NULL",
    "TRUE",
    "FALSE",
    "STRING",
    "NUMBER",

    NULL
};

/*----------------------------------------------------------------------------
|   Types
|
\---------------------------------------------------------------------------*/







>







199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
    "ARRAY",
    "OBJECT",
    "NULL",
    "TRUE",
    "FALSE",
    "STRING",
    "NUMBER",
    "BOOLEAN",
    NULL
};

/*----------------------------------------------------------------------------
|   Types
|
\---------------------------------------------------------------------------*/
3172
3173
3174
3175
3176
3177
3178


3179
3180
3181
3182
3183
3184
3185
    int          indent,
    int          outputFlags,
    int          level,
    int          inside
    )
{
    domTextNode *textNode;


    
    switch (node->nodeType) {
    case TEXT_NODE:
        if (inside == JSON_OBJECT) {
            /* We're inside a JSON object. A text node can not be
             * meaningful interpreted as member of an object. Ignore
             * the node */







>
>







3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
    int          indent,
    int          outputFlags,
    int          level,
    int          inside
    )
{
    domTextNode *textNode;
    Tcl_Obj *valueObj;
    int bool;
    
    switch (node->nodeType) {
    case TEXT_NODE:
        if (inside == JSON_OBJECT) {
            /* We're inside a JSON object. A text node can not be
             * meaningful interpreted as member of an object. Ignore
             * the node */
3205
3206
3207
3208
3209
3210
3211














3212
3213
3214
3215
3216
3217
3218
            break;
        case JSON_TRUE:
            writeChars(jstring, channel, "true",4);
            break;
        case JSON_FALSE:
            writeChars(jstring, channel, "false",5);
            break;














        case JSON_STRING:
            /* Fall through */
        default:
            tcldom_AppendEscapedJSON (jstring, channel,
                                      textNode->nodeValue,
                                      textNode->valueLength);
            break;







>
>
>
>
>
>
>
>
>
>
>
>
>
>







3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
            break;
        case JSON_TRUE:
            writeChars(jstring, channel, "true",4);
            break;
        case JSON_FALSE:
            writeChars(jstring, channel, "false",5);
            break;
        case JSON_BOOLEAN:
            valueObj = Tcl_NewStringObj (textNode->nodeValue,
                                         textNode->valueLength);
            if (Tcl_GetBooleanFromObj(NULL, valueObj, &bool) == TCL_OK) {
                if (bool) {
                    writeChars(jstring, channel, "true",4);
                } else {
                    writeChars(jstring, channel, "false",5);
                }
                Tcl_DecrRefCount (valueObj);
                break;
            }
            Tcl_DecrRefCount (valueObj);
            /* Fall through */
        case JSON_STRING:
            /* Fall through */
        default:
            tcldom_AppendEscapedJSON (jstring, channel,
                                      textNode->nodeValue,
                                      textNode->valueLength);
            break;
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
                        return TCL_ERROR;
                    }
                }
                node->info = jsonType;
                SetIntResult(jsonType);
                return TCL_OK;
            }
            if (node->info > 7) {
                SetResult(jsonTypes[0]);
            } else {
                SetResult(jsonTypes[node->info]);
            }
            return TCL_OK;
            
        TDomThreaded(







|







6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
                        return TCL_ERROR;
                    }
                }
                node->info = jsonType;
                SetIntResult(jsonType);
                return TCL_OK;
            }
            if (node->info > 8) {
                SetResult(jsonTypes[0]);
            } else {
                SetResult(jsonTypes[node->info]);
            }
            return TCL_OK;
            
        TDomThreaded(
6642
6643
6644
6645
6646
6647
6648
6649

6650
6651
6652
6653
6654
6655
6656
        "NONE",
        "ARRAY",
        "OBJECT",
        "NULL",
        "TRUE",
        "FALSE",
        "STRING",
        "NUMBER"

    };

    Tcl_ResetResult (interp);

    /*------------------------------------------------------------------------
    |   Need parent node to get the owner document and to append new 
    |   child tag to it. The current parent node is stored on the stack.







|
>







6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
6671
6672
6673
6674
        "NONE",
        "ARRAY",
        "OBJECT",
        "NULL",
        "TRUE",
        "FALSE",
        "STRING",
        "NUMBER",
        "BOOLEAN"
    };

    Tcl_ResetResult (interp);

    /*------------------------------------------------------------------------
    |   Need parent node to get the owner document and to append new 
    |   child tag to it. The current parent node is stored on the stack.
Changes to tests/dom.test.
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
    catch {dom createDocumentNode -foo NULL docNode} errMsg
    set errMsg
} {bad option "-foo": must be -jsonType}

test dom-8.11 {createDocumentNode} {
    catch {dom createDocumentNode -jsonType FOO docNode} errMsg
    set errMsg
} {bad jsonType "FOO": must be NONE, ARRAY, OBJECT, NULL, TRUE, FALSE, STRING, or NUMBER}

test dom-8.12 {createDocumentNode - method check} {
    set docNode [dom createDocumentNode]
    set result [$docNode documentElement]
    $docNode delete
    set result
} {}







|







1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
    catch {dom createDocumentNode -foo NULL docNode} errMsg
    set errMsg
} {bad option "-foo": must be -jsonType}

test dom-8.11 {createDocumentNode} {
    catch {dom createDocumentNode -jsonType FOO docNode} errMsg
    set errMsg
} {bad jsonType "FOO": must be NONE, ARRAY, OBJECT, NULL, TRUE, FALSE, STRING, NUMBER, or BOOLEAN}

test dom-8.12 {createDocumentNode - method check} {
    set docNode [dom createDocumentNode]
    set result [$docNode documentElement]
    $docNode delete
    set result
} {}
Changes to tests/domjson.test.
37
38
39
40
41
42
43

44
45
46
47
48
49
50
    dom createNodeCmd textNode    t
    dom createNodeCmd -jsonType TRUE textNode true
    dom createNodeCmd -jsonType FALSE textNode false
    dom createNodeCmd -jsonType NULL textNode null
    dom createNodeCmd -jsonType NUMBER textNode number
    dom createNodeCmd cdataNode   cdata
    dom createNodeCmd piNode      pi

}

test json-1.1 {Parse JSON} {
    set doc [dom parse -json {{"a":"avalue","b":"bvalue","c":0.123}}]
    set result [$doc asXML -indent none]
    $doc delete
    set result







>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
    dom createNodeCmd textNode    t
    dom createNodeCmd -jsonType TRUE textNode true
    dom createNodeCmd -jsonType FALSE textNode false
    dom createNodeCmd -jsonType NULL textNode null
    dom createNodeCmd -jsonType NUMBER textNode number
    dom createNodeCmd cdataNode   cdata
    dom createNodeCmd piNode      pi
    dom createNodeCmd -jsonType BOOLEAN textNode boolean
}

test json-1.1 {Parse JSON} {
    set doc [dom parse -json {{"a":"avalue","b":"bvalue","c":0.123}}]
    set result [$doc asXML -indent none]
    $doc delete
    set result
2784
2785
2786
2787
2788
2789
2790
2791







































2792
2793
2794
2795
2796
2797
2798
        nodeCmds::null
        nodeCmds::true
        nodeCmds::false
    }
    set result [$doc asXML -indent none]
    $doc delete
    set result
} {<doc></doc>}







































}

test json-9.1 {cloneNode -deep} {
    dom parse -json {[["a",1,"b",{"foo":"bar","baz":"boo"},null],"",null]} doc
    dom createDocument some other
    $other documentElement root
    $root appendChild [[$doc firstChild] cloneNode -deep]







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
        nodeCmds::null
        nodeCmds::true
        nodeCmds::false
    }
    set result [$doc asXML -indent none]
    $doc delete
    set result
} {<doc/>}

test json-8.10 {text node json type BOOLEAN} {
    set doc [dom createDocumentNode]
    $doc jsonType ARRAY
    $doc appendFromScript {
        nodeCmds::boolean foo
        nodeCmds::boolean true
        nodeCmds::boolean false
    }
    set result [$doc asJSON]
    $doc delete
    set result
} {["foo",true,false]}

test json-8.11 {text node json type BOOLEAN} {
    set doc [dom createDocumentNode]
    $doc jsonType ARRAY
    foreach value {foo 1 0} {
        set newtextnode [$doc createTextNode $value]
        $newtextnode jsonType BOOLEAN
        $doc appendChild $newtextnode
    }
    set result [$doc asJSON]
    $doc delete
    set result
} {["foo",true,false]}

test json-8.12 {text node json type BOOLEAN} {
    set doc [dom createDocumentNode]
    $doc jsonType ARRAY
    $doc appendFromScript {
        foreach value {foo 1 0 true false TRue falSE yes no YES NO bar} {
            nodeCmds::boolean $value
        }
    }
    set result [$doc asJSON]
    $doc delete
    set result
} {["foo",true,false,true,false,true,false,true,false,true,false,"bar"]}
}

test json-9.1 {cloneNode -deep} {
    dom parse -json {[["a",1,"b",{"foo":"bar","baz":"boo"},null],"",null]} doc
    dom createDocument some other
    $other documentElement root
    $root appendChild [[$doc firstChild] cloneNode -deep]