JQL
A JSON Query Language CLI tool built with Rust
๐ฆ
๐
Core philosophy
-
๐ฆ Stay lightweight -
๐ฎ Keep its features as simple as possible -
๐ง Avoid redundancy -
๐ก Provide meaningful error messages -
โ๏ธ Eat JSON as input, process, output JSON back
๐
Installation
Cargo
cargo install jql
Archlinux
The AUR package is maintained by @frol.
yay -S jql
Homebrew
brew install jql
๐ ๏ธ
Usage
If you find some of the following examples confusing, please have a look at The JavaScript Object Notation (JSON) Data Interchange Format.
Root selection
"This is a valid JSON text with one value"
jql '.' example.json
"This is a valid JSON text with one value"
Child selection
{
"some": {
"property": "yay!"
}
}
jql '"some"."property"' example.json
"yay!"
Index selection
{
"primes": [7, 11, 13]
}
jql '"primes".[0]' example.json
7
Please note that the following is also valid:
jql '"primes"[0]"' example.json
7
You can also select a set of indexes:
jql '"primes".[2,0]' example.json
[13, 7]
Range selection
{
"cats": [{ "first": "Pixie" }, { "second": "Kitkat" }, { "third": "Misty" }]
}
jql '"cats".[1:2]' example.json
[
{
"second": "Kitkat"
},
{
"third": "Misty"
}
]
Please note that you can reverse it:
jql '"cats".[2:1]' example.json
[
{
"third": "Misty"
},
{
"second": "Kitkat"
}
]
Bonus, you can do it again to get it back:
jql '"cats".[2:1].[1:0]' example.json
[
{
"second": "Kitkat"
},
{
"third": "Misty"
}
]
Please note that you can still access the children:
jql '"cats".[2:1].[0]."third"' example.json
"Misty"
You can also use the start or the end position as a range selector:
jql '"cats".[1:]' example.json
[
{
"second": "Kitkat"
},
{
"third": "Misty"
}
]
jql '"cats".[:1]' example.json
[
{
"first": "Pixie"
},
{
"second": "Kitkat"
}
]
Array selection
{
"primes": [7, 11, 13]
}
jql '"primes".[]' example.json
[7, 11, 13]
Please note that this is basically an alias for a full range selection:
jql '"primes".[0:2]' example.json
Property selection
{
"object": { "a": 1, "b": 2, "c": 3 }
}
jql '"object".{"a","c"}' example.json
{
"a": 1,
"c": 3
}
Property selection can also be used with indexes and ranges. Please note that in this case a remapping/transformation is applied to the JSON data:
{
"alpha": "red",
"beta": "green",
"gamma": "blue"
}
jql '{[2,0,1]}' example.json
{
"2": "blue",
"0": "red",
"1": "green"
}
jql '{[1:2]}' example.json
{
"1": "green",
"2": "blue"
}
This is pretty unusual but it might help in some scenarios when e.g. one wants to extract some properties out of a complex JSON structure based on their order:
{
"some-property": [
{
"key1": [
{
"subkey1": "value"
}
],
"key2": 123
},
{
"key3": [
{
"subkey3": "value"
}
],
"key4": "something"
}
]
}
jql '.."some-property"|{[0]}|"0"' example.json
[
{
"subkey1": "value"
},
{
"subkey3": "value"
}
]
Multi-selection
{
"one": [1, 2, 3],
"two": 2,
"three": 3
}
jql '"one".[2:0],"two","three"' example.json
[[3, 2, 1], 2, 3]
Filter
{
"laptops": [
{
"laptop": {
"brand": "Apple",
"options": ["a", "b", "c"]
}
},
{
"laptop": {
"brand": "Asus",
"options": ["d", "e", "f"]
}
}
]
}
jql '"laptops"|"laptop"' example.json
[
{
"brand": "Apple",
"options": ["a", "b", "c"]
},
{
"brand": "Asus",
"options": ["d", "e", "f"]
}
]
You can also combine a filter with a child selection, a multi-selection and ranges at the same time:
jql '"laptops"|"laptop"."brand"' example.json
["Apple", "Asus"]
jql '"laptops".[1:0]|"laptop"."brand","laptops"|"laptop"."brand"' example.json
[
["Asus", "Apple"],
["Apple", "Asus"]
]
Please note that you can combine filters to achieve the same result:
jql '"laptops".[1:0]|"laptop"|"brand","laptops"|"laptop"|"brand"' example.json
[
["Asus", "Apple"],
["Apple", "Asus"]
]
Flatten arrays
{
"dna": [[[[["c", "a", "c"]]]], "g", "t", [[["a", ["t"]]]]]
}
jql '.."dna"' example.json
["c", "a", "c", "g", "t", "a", "t"]
Truncate
The truncate selector !
can be used to stop walking the children's values and to explore an unknown JSON file / structure. Each children is then transformed into a JSON primitive for convenience, e.g.:
primitive | value | result |
---|---|---|
object | { "a": 1, "b": 2, "c": 3 } |
{} |
array | [1, 2, 3] |
[] |
string | "foo" |
"foo" |
number | 666 |
666 |
null | null |
null |
{
"foo": {
"a": null,
"b": "bar",
"c": 1337,
"d": {
"woot": [1, 2, 3]
}
}
}
jql '.!' example.json
{
"foo": {}
}
jql '"foo"!' example.json
{
"a": null,
"b": "bar",
"c": 1337,
"d": {}
}
Special characters
{
".valid": 1337,
"": "yeah!",
"\"": "yup, valid too!"
}
jql '".valid"' example.json
1337
jql '""' example.json
"yeah!"
jql '"\""' example.json
"yup, valid too!"
๐ป
Shell integration
How to save the output
jql '"foo"."bar"' input.json > output.json
How to read from stdin
cat example.json | jql '"foo"."bar"'
๐ค
Available flags Help
jql -h
jql --help
Check
The command will return a matching exit code based on the validity of the JSON content or file provided. No selector is needed in this case!
jql --c example.json
jql --check example.json
Please note that this flag is exclusive.
Version
jql -V
jql --version
Inlining the JSON output
jql -i '"some"."selector"' example.json
jql --inline '"some"."selector"' example.json
Raw output
Use the raw-output
flag on a string selection to directly return the raw string without JSON double-quotes:
echo "{\"foo\":\"bar\"}" | jql --raw-output '"foo"'
bar
echo "{\"foo\":\"bar\"}" | jql -r '"foo"'
bar
Streaming
Use the stream
flag to read a stream of JSON lines:
while true; do echo '{"foo": 2}'; sleep 1; done | jql '.!' --stream
while true; do echo '{"foo": 2}'; sleep 1; done | jql '.!' -s
Please note that this option is only about reading valid JSON output streamed line by line (e.g. Docker logs with the --follow
flag). This is not an option to read an incomplete streamed content (e.g. a very large input)!
๐ฟ
Library
This crate is both a binary (the CLI tool) and a library that can be directly used https://docs.rs/crate/jql/.
โก
Performance
Some benchmarks comparing a set of similar functionalities provided by this tool and jq are available here.