select values out of nested JSON, YAML and XML documents

Documentation

Synopsis

treesift [options] SELECTOR [FILE ...]

treesift reads each FILE, or standard input when no file is given, and prints every value matching SELECTOR. Multiple files are processed in order and their results are concatenated. Documents that contain nothing but whitespace are skipped rather than treated as an error.

Selector syntax

A selector is a sequence of steps. Each step narrows or expands the set of values carried forward from the previous one, starting from the whole document.

a.b
Take key b from object a. A key that does not exist contributes nothing rather than raising an error, so a selector that matches nothing simply prints nothing.
a[2]
Take the element at index 2 of list a. Indices are zero based and negative indices count from the end.
a[]
Expand list a into its elements, flattening one level. Applied to an object it expands into that object's values.
a.*
Every value of object a, equivalent to a[] for objects. Written as [*] it reads more naturally next to an index.
a.b
When a is a list of objects rather than an object, a key step is distributed over its elements. This makes users.name behave like users[].name, which is almost always what was meant.

Quoting is available for keys that contain a dot or a bracket: write ['odd.key'] to select a key literally.

Options

-f, --format {json,yaml,xml}
Force the input format instead of detecting it.
-r, --raw
Print bare strings without JSON quoting. Values that are not strings are unaffected, so mixed results stay unambiguous.
-c, --compact
One result per line with no indentation. Useful when the output is going into another command rather than onto a screen.
-s, --sort-keys
Sort object keys in the output. Handy when diffing two runs.
-e, --exit-code
Exit with status 1 when the selector matched nothing, so that a shell script can branch on absence without inspecting the output.
-V, --version
Print the version and exit.

Input format detection

The format is taken from the file extension when there is one: .json, .yaml, .yml and .xml are recognised. Otherwise the first non-blank character decides — < means XML, { or [ mean JSON, and anything else is treated as YAML. Since JSON is valid YAML this fallback is safe in practice, but --format is there for the cases where it guesses wrong.

JSON input may contain several concatenated documents, and YAML input may contain several documents separated by ---. Both are read in full and their results are concatenated.

XML mapping

XML has no direct equivalent of objects and lists, so it is mapped before selection. Attributes become keys. Repeated child elements become a list under the shared tag name. An element with text and no children becomes that text, and if it has both, the text is available as #text. The root element keeps its tag, so selectors start with the root name.

Exit status

StatusMeaning
0Success.
1Nothing matched, and --exit-code was given.
2Bad arguments, unreadable file, or a document that failed to parse.
130Interrupted.

A closed pipe is not an error: treesift ... | head -1 exits cleanly instead of reporting a broken pipe.