# json_shell_utils.tcl
# General purpose Tcl module for JSON creation and parsing using Linux shell tools `jo` and `jq`.
namespace eval json_shell {
# -------------------------------------------------------------------------
# Initialization
# Check for required external shell commands.
# -------------------------------------------------------------------------
proc init {} {
if {[catch {exec which jo}]} {
return -code error "Initialization failed: 'jo' command is not installed or not in PATH."
}
if {[catch {exec which jq}]} {
return -code error "Initialization failed: 'jq' command is not installed or not in PATH."
}
}
# Run initialization upon sourcing the file
init
# -------------------------------------------------------------------------
# json_shell::create
# -------------------------------------------------------------------------
# Converts a Tcl dictionary into a JSON string using `jo`.
#
# Arguments:
# dictData - A standard Tcl dictionary of key-value pairs.
#
# Returns:
# A JSON formatted string.
# -------------------------------------------------------------------------
proc create {dictData} {
set jo_args {}
dict for {k v} $dictData {
# Standard jo assignment key=value.
# jo automatically handles type inference (numbers, booleans) and escapes strings.
lappend jo_args "${k}=${v}"
}
# Safely execute `jo` with all arguments properly expanded
set cmd [list exec jo {*}$jo_args]
if {[catch {eval $cmd} result]} {
return -code error "json_shell::create failed: $result"
}
return $result
}
# -------------------------------------------------------------------------
# json_shell::parse
# -------------------------------------------------------------------------
# Converts a JSON string into a native Tcl dictionary using `jq`.
#
# Arguments:
# json_string - A valid JSON string to parse.
#
# Returns:
# A Tcl dictionary representing the top-level keys and values.
# -------------------------------------------------------------------------
proc parse {json_string} {
# Return empty dict if string is entirely empty or just whitespace
if {[string trim $json_string] eq ""} {
return [dict create]
}
# We use `jq` with the -j (join) flag to output keys and values separated by a NULL byte (\0).
# This completely eliminates issues with newlines, spaces, or quotes inside the JSON values.
# to_entries converts objects (and arrays to integer-keyed objects), allowing safe iteration.
set jq_filter {to_entries? | .[]? | .key, "\u0000", (.value|tostring), "\u0000"}
# We pipe the JSON string into standard input of `jq`
set cmd [list exec jq -j $jq_filter << $json_string]
if {[catch {eval $cmd} result]} {
return -code error "json_shell::parse failed: $result"
}
# If result is empty, return empty dict
if {$result eq ""} {
return [dict create]
}
# The result ends with a trailing NULL byte because of the filter. Trim it off.
set result [string trimright $result "\0"]
# Split by NULL byte to get a flat list, which seamlessly casts to a Tcl dictionary.
set dictList [split $result "\0"]
return $dictList
}
}
Thursday, July 23, 2026
json_shell_utils.tcl
Subscribe to:
Post Comments (Atom)
-
Given this module some attention today. Added some of the more package wide options to the module and created customised handler for settin...
-
Spent some time today creating some simple howto-tutorials on creating standalone Tcl/Gnocl applications using freewrap. The process is almo...
-
Linux distros have heaps of pre-installed icons ready for use. I recently needed to create a toolbar menu which needed to access a set of un...
No comments:
Post a Comment