This repository provides json
, a self-contained Python script intended to simplify command-line JSON activities. This tool's primary intent is to parse and interrogate JSON streams in a way convenient for scripting.
Key features include:
- Formatting unformatted JSON with indentation, sorting
- Detailed information about JSON parse failures
- Data interrogation and access
- Value formatting for downstream use
json
[-h]
[-l,--lookup PATTERN]
[-S,--lookup-sep S]
[-e,--escape | -p,--print-value]
[-1,--oneline | -i,--indent N]
[-s,--sort-keys]
[-w,--width N]
[-C,--no-color]
[-v,--verbose]
[path [path ...]]
-h
- print the help message and exit-l PATTERN
or--lookup PATTERN
- extract data from the json (see Value Lookup below)-S S
or--lookup-sep S
- Join multiple--lookup
values into a single string-e
or--escape
- escape the output for later JSON parsing-p
or--print-value
- print the output with no escaping-1
or--oneline
- output on a single line without indentation-i N
or--indent N
- indent output with this many spaces (default: 2)-s
or--sort-keys
- sort JSON keys-w N
or--width N
- amount of context to include in error messages (default: 8)-C
or--no-color
- disable color formatting in error messages-v
or--verbose
- output diagnostic information[path [path ...]]
- file(s) to process; defaults to stdin if omitted
The following argument combinations are mutually-exclusive:
-e
or--escape
with-p
or--print-value
-1
or--oneline
with-i N
or--indent N
The following arguments apply only to error messages:
-w N
or--width N
-C
or--no-color
The following arguments are ignored if -p
or --print-value
are given:
-1
or--oneline
-i N
or--indent N
-s
or--sort-keys
-e
or--escape
The -l,--lookup PATTERN
argument permits extracting data from a JSON stream without needing to write extra code. PATTERN
is an XPath-inspired sequence of substrings separated by slashes /
.
This tool is intelligent enough to interpret numeric substrings as indexes when examining an array and keys when examining an object.
-l data
is interpreted asjson["data"]
-l data/0
is interpreted asjson["data"]["0"]
ifjson["data"]
is an object.-l data/0
is interpreted asjson["data"][0]
ifjson["data"]
is an array.
Value extraction logic is roughly as follows:
- If the data is
String
orArray
:- If the substring is numeric, obtain the element at that index.
- Negative indexes are interpreted as relative to the end of the
String
orArray
.
- Negative indexes are interpreted as relative to the end of the
- If the substring is a slice (
<start>:<stop>
), obtain either the substring or sub-array between those two indexes.- The slice
<start>:
is interpreted as "all elements at or after index<start>
". The index can be negative. - The slice
:<stop>
is interpreted as "all elements before<stop>
". The index can be negative. - The slice
:
resolves to the entire sequence and is effectively a no-op.
- The slice
- Otherwise, issue a warning and return the data as-is.
- If the substring is numeric, obtain the element at that index.
- If the data is an
Object
:- If the data contains the substring as a key, obtain that key's value.
- Otherwise, issue a warning and return the data as-is.
- If the data is an
Integer
orBoolean
, issue a warning and return the data as-is. - If the final substring contains
"!"
, then format the obtained value depending on the characters to the right of the"!"
:!i
or!int
convert the obtained value to an integer.None
is returned if this fails.!f
or!float
convert the obtained vlaue to a float.None
is returned if this fails.!r
or!repr
replace the obtained value withrepr(value)
.
A substring is considered numeric if it contains only digits between 0
and 9
, optionally with a leading hyphen -
.
If more than one -l,--lookup PATTERN
argument is given, then the output is an array containing each lookup result. However, if -S,--lookup-sep
is specified, then those results are joined into a single string using the separator string.
Failure applying a pattern is not a fatal error. If a pattern cannot be applied, either because it's invalid or the object doesn't have anything matching the pattern, this program issues a warning and leaves the object unchanged.
Assume the following JSON input:
{
"data": [
{
"name": "value",
"0": "https://example.com/value/0",
"1": "https://example.com/value/1"
},
{
"name": "value-2",
"0": "https://example.com/value-2/0",
"1": "https://example.com/value-2/1"
}
]
}
Lookup Pattern | Python Equivalent | Final Value |
---|---|---|
data/0 |
json["data"][0] |
{"name": "value", "0": "https://example.com/value/0", "1": "https://example.com/value/1"} |
data/1 |
json["data"][1] |
{"name": "value-2", "1": "https://example.com/value-2/0", "1": "https://example.com/value-2/1"} |
data/-1 |
json["data"][-1] |
{"name": "value-2", "1": "https://example.com/value-2/0", "1": "https://example.com/value-2/1"} |
data/0/name |
json["data"][0]["name"] |
"value" |
data/0/0 |
json["data"][0]["0"] |
"https://example.com/value/0" |
data/1/0 |
json["data"][1]["0"] |
"https://example.com/value-2/0" |
data/-1/name |
json["data"][-1]["name"] |
"value-2" |
data/0/name/0 |
json["data"][0]["name"][0] |
"v" |
data/0/name/1: |
json["data"][0]["name"][0] |
"alue" |
0
on success1
if parsing any input stream raised aJSONDecodeError
It would be convenient to allow wildcards or multi-matching in -l,--lookup
. For instance, given the following data:
{
"data": [
{
"name": "first",
"value": "example.com"
},
{
"name": "second",
"value": "example.net"
},
{
"name": "third",
"value": "example.org"
}
]
}
the argument -l data/*/name
could give ["first", "second", "third"]
, the argument -l data/1:/name
could give ["second", "third"]
, the argument -l data/1:/name/0
could give ["f", "s", "t"]
, and so on. Note that the current implementation forbids this, for two reasons:
data/1:/name/0
attempts to get the index"name"
of an array, which is invalid.- Assuming we allow a more relaxed pattern-matching approach,
data/1:/name
could give[entry["name"] for entry in data[1:]]
, butdata/1:/name/0
would only extract the first element of that array.
There would need to be a distinction between "get this value for this item" versus "get this value for all items in this collection".