TCL/C extension for parsing JSON
Contact: neophytos (at) gmail (dot) com
https://github.com/jerily/tjson%|%tjson git repo%|%
**Releases**
* https://github.com/jerily/tjson/releases/tag/v1.0.11%|%v.1.0.11%|% (2024-03-10 - initial support for TCL 9)
* https://github.com/jerily/tjson/releases/tag/v1.0.10%|%v.1.0.10%|% (20293-10-01 - trace var in create and parse commands)
* v.1.0.9 (2023-09-30 - windows support)
* v.1.0.8 (2023-09-28 - bug fix release)
* v.1.0.6 (2023-09-28 - macOS support / more flexible build/install)
**Features**
* Simple transformations between TCL and JSON using a typed notation/spec.
* Manipulate objects and arrays (add, replace, and delete items and elements).
* Perform JSONPath queries
* Serialize to JSON, pretty JSON, or a simple TCL structure i.e. string, list, and dict.
======
# Parse JSON string and return a simple TCL structure
# ::tjson::json_to_simple json_string
::tjson::json_to_simple {{"a": 1, "b": true, "c": [1, 2, 3], "d": {"d1":"a", "d2":"b"}}} true
=> a 1 b 1 c {1 2 3} d {d1 a d2 b}
# Parse JSON string and return a typed TCL structure
# ::tjson::json_to_typed json_string
::tjson::json_to_typed {{"a": 1, "b": true, "c": [1, 2, 3], "d": {"d1":"a", "d2":"b"}}}
=> M {a {N 1} b {BOOL 1} c {L {{N 1} {N 2} {N 3}}} d {M {d1 {S a} d2 {S b}}}}
# Serialize a typed TCL structure to JSON.
# ::tjson::typed_to_json typed_spec
::tjson::typed_to_json {M {a {N 1} b {BOOL 1} c {L {{N 1} {N 2} {N 3}}} d {M {d1 {S a} d2 {S b}}}}}
=> {"a": 1, "b": true, "c": [1, 2, 3], "d": {"d1": "a", "d2": "b"}}
# Escape JSON string
# ::tjson::escape_json_string string
::tjson::escape_json_string "hello\nworld\n"
=> hello\"world\n
======
Here is an example of parsing and manipulating the JSON node:
======
package require tjson
set node_handle [::tjson::parse {
{ "store": {
"book": [
{ "category": "reference", "author": "Nigel Rees",
"title": "Sayings of the Century", "price": "8.95" },
{ "category": "fiction", "author": "Evelyn Waugh",
"title": "Sword of Honour", "price": "12.99" },
{ "category": "fiction", "author": "Herman Melville",
"title": "Moby Dick", "isbn": "0-553-21311-3",
"price": "8.99" },
{ "category": "fiction", "author": "J. R. R. Tolkien",
"title": "The Lord of the Rings", "isbn": "0-395-19395-8",
"price": "22.99" }
],
"bicycle": { "color": "red", "price": "19.95" }
}
}}]
set store_handle [::tjson::get_object_item $node_handle store]
::tjson::add_item_to_object $store_handle car [list M \
[list brand {S "Mercedes"} color {S blue} price {N 19876.57}]]
set book_handle [::tjson::get_object_item $store_handle book]
::tjson::add_item_to_array $book_handle [list M \
[list \
category {S "fiction"} \
author {S "Fyodor Dostoevsky"} \
title {S "Brothers Karamazov"} \
isbn {S "0679410031"} \
price {N "22.19"}]]
puts [::tjson::to_pretty_json $node_handle]
::tjson::destroy $node_handle
======
It is possible to perform JSONPath queries as follows:
======
set jsonpath {$.store..author}
set item_handles [::tjson::query $handle $jsonpath]
lmap x $item_handles {::tjson::to_simple $x}
======
**Performance**
Download this file: https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json
======
package require tjson
set fp [open "spec3.json"]
set data [read $fp]
close $fp
puts [time {::tjson::destroy [::tjson::parse $data]} 1000]
======
=> 27935.83 microseconds per iteration