NAME

JQ::Lite - A lightweight jq-like JSON query engine in Perl

VERSION

Version 1.32

SYNOPSIS

use JQ::Lite;

my $jq = JQ::Lite->new;
my @names = $jq->run_query($json_text, '.users[].name');

say encode_json($_) for @names;

Command-line usage mirrors the library API:

cat users.json | jq-lite '.users[].name'
jq-lite -r '.users[] | .name' users.json

OVERVIEW

JQ::Lite is a lightweight, pure-Perl JSON query engine inspired by the jq command-line tool. It gives you jq-style queries without requiring any XS components or external binaries, so you can embed powerful JSON exploration directly inside Perl scripts or run it from the included command-line client.

GETTING STARTED

1. Decode or obtain a JSON string.
my $json_text = do { local $/; <DATA> };
2. Build a JQ::Lite instance (enable raw = 1> to receive raw scalars instead of JSON-encoded structures).
my $jq = JQ::Lite->new(raw => 1);
3. Run a jq-style query and iterate over the returned Perl values.
for my $value ($jq->run_query($json_text, '.users[] | select(.active)')) {
    say $value->{name};
}

Need a REPL-style experience? Run jq-lite with no query to enter interactive mode, then experiment with filters until you find the data you need.

FEATURES AT A GLANCE

  • Pure Perl implementation – no non-core dependencies or XS

  • Familiar jq-inspired traversal syntax (.foo, .foo[], .foo?, array slicing)

  • Extensive library of filters for aggregations, reshaping, and string manipulation

  • Pipeline-friendly design that mirrors jq's mental model

  • Command-line wrapper with colour output, YAML support, and decoder selection

  • Interactive shell for exploring queries line-by-line

LIBRARY INTERFACE

new

my $jq = JQ::Lite->new;

Creates a new instance. Pass raw = 1> to receive plain scalars (like jq's -r) instead of JSON-encoded structures. Additional options may be added in future versions.

METHODS

run_query

my @results = $jq->run_query($json_text, $query);

Runs a jq-like query against the given JSON string. Returns a list of matched results. Each result is a Perl scalar (string, number, arrayref, hashref, etc.) depending on the query.

In scalar context the first result is returned, mirroring jq's behaviour.

COMMAND-LINE CLIENT

The distribution ships with jq-lite, a drop-in jq-style executable that reads JSON from STDIN or files, honours common jq flags (-r, -c, -n, -s), and supports coloured output. Run jq-lite --help for the full option list, or jq-lite --help-functions to display every built-in helper.

SUPPORTED SYNTAX

Traversal and extraction

  • .key.subkey

  • .array[0] (index access)

  • .array[] (flatten arrays)

  • .key? (optional key access without throwing errors)

Filtering and control flow

  • select(.key 1 and .key2 == "foo")>

    Evaluates jq-style conditional expressions. Conditions are treated as filters executed against the current input; the first branch whose condition produces a truthy result has its filter evaluated and emitted. Optional elif clauses cascade additional tests, and the optional else filter runs only when no prior branch matched. When no else clause is supplied and every condition is falsey the expression yields no output.

    Example:

    if .score >= 90 then "A"
    elif .score >= 80 then "B"
    else "C"
    end
  • reduce expr as $var (init; update) (accumulate values with lexical bindings)

  • foreach expr as $var (init; update [; extract]) (stream results while folding values)

Aggregation and grouping

  • group_by(.field)

  • group_count(.field)

  • sort_by(.key), sort_desc()

    Sort array elements in descending order using smart numeric/string comparison.

    Example:

    .scores | sort_desc

    Returns:

    [100, 75, 42, 12]
  • unique_by(.key)

  • .key | count (count items or fields)

  • .[] | select(...) | count (combine flattening + filter + count)

  • sum_by(.field), avg_by(.field), median_by(.field), percentile(p), min_by(.field), max_by(.field)

    Project numeric values from each element and compute aggregated statistics (sum, average, median, percentiles, min/max, etc.).

String and array helpers

  • .array | map(.field) | join(", ")

    Concatenate array elements with a custom separator string.

    Example:

    .users | map(.name) | join(", ")

    Results in:

    "Alice, Bob, Carol"
  • split(separator)

    Split string values (and arrays of strings) using a literal separator.

    Example:

    .users[0].name | split("")

    Results in:

    ["A", "l", "i", "c", "e"]
  • explode()

    Convert strings into arrays of Unicode code points. When applied to arrays the conversion happens element-wise, while non-string values (including hashes) are passed through untouched. This mirrors jq's explode helper and pairs with implode for round-trip transformations.

    Example:

    .title | explode

    Returns:

    [67, 79, 68, 69]
  • implode()

    Perform the inverse of explode by turning arrays of Unicode code points back into strings. Nested arrays are processed recursively so pipelines like explode | implode work over heterogeneous structures. Non-array inputs pass through unchanged.

    Example:

    .codes | implode

    Returns:

    "CODE"
  • keys_unsorted()

    Returns the keys of an object without sorting them, mirroring jq's keys_unsorted helper. Arrays yield their zero-based indices, while non-object/array inputs return undef to match the behaviour of keys.

    Example:

    .profile | keys_unsorted
  • values()

    Returns all values of a hash as an array. Example:

    .profile | values
  • paths()

    Enumerates every path within the current value, mirroring jq's paths helper. Each path is emitted as an array of keys and/or indices leading to objects, arrays, and their nested scalars. Scalars (including booleans and null) yield a single empty path, while empty arrays and objects contribute only their immediate location.

    Example:

    .user | paths

    Returns:

    [["name"], ["tags"], ["tags",0], ["tags",1], ["active"]]
  • leaf_paths()

    Enumerates only the paths that terminate in non-container values, mirroring jq's leaf_paths helper. This is equivalent to paths(scalars) in jq.

    Example:

    .user | leaf_paths

    Returns:

    [["name"], ["tags",0], ["tags",1], ["active"]]
  • getpath(path)

    Retrieves the value referenced by the supplied path array (or filter producing path arrays), mirroring jq's getpath/1. Literal JSON arrays can be passed directly while expressions such as paths() are evaluated against the current input to collect candidate paths. When multiple paths are returned the helper yields an array of values in the same order.

    Examples:

    .profile | getpath(["name"])          # => "Alice"
    .profile | getpath(["emails", 1])     # => "alice.work\@example.com"
    .profile | getpath(paths())
  • setpath(path; value)

    Sets or creates a value at the supplied path, following jq's setpath/2 semantics. The first argument may be a literal JSON array or any filter that emits path arrays. The second argument can be a literal (including JSON objects/arrays) or another filter evaluated against the current input. Nested hashes/arrays are automatically created as needed, and the original input is never mutated.

    Examples:

    .settings | setpath(["flags", "beta"]; true)
    .user     | setpath(["profile", "full_name"]; .name)
  • pick(key1, key2, ...)

    Builds a new object containing only the supplied keys. When applied to arrays of objects, each element is reduced to the requested subset while non-object values pass through unchanged.

    Example:

    .users | pick("name", "email")

    Returns:

    [{ "name": "Alice", "email": "alice\@example.com" },
     { "name": "Bob" }]
  • merge_objects()

    Merges arrays of objects into a single hash reference using last-write-wins semantics. Non-object values within the array are ignored. When no objects are found, an empty hash reference is returned. Applying the helper directly to an object returns a shallow copy of that object.

    Example:

    .items | merge_objects()

    Returns:

    { "name": "Widget", "value": 2, "active": true }
  • to_entries()

    Converts objects (and arrays) into an array of entry hashes, each consisting of key and value fields in the jq style. Array entries use zero-based index values for the key so they can be transformed uniformly.

    Example:

    .profile | to_entries
    .tags    | to_entries
  • from_entries()

    Performs the inverse of to_entries. Accepts arrays containing { key = ..., value => ... }> hashes or [key, value] tuples and rebuilds a hash from them. Later entries overwrite earlier ones when duplicate keys are encountered.

    Example:

    .pairs | from_entries
  • with_entries(filter)

    Transforms objects by mapping over their entries with the supplied filter, mirroring jq's with_entries. Each entry is exposed as a { key, value } hash to the filter, and any entries filtered out are dropped prior to reconstruction.

    Example:

    .profile | with_entries(select(.key != "password"))
  • map_values(filter)

    Applies the supplied filter to every value within an object, mirroring jq's map_values. When the filter returns no results for a key the entry is removed, allowing constructs such as map_values(select(. 0))> to prune falsy values. Arrays are processed element-wise, so arrays of objects can be transformed in a single step.

    Example:

    .profile | map_values(tostring)

BUILT-IN FILTER CATALOGUE

Beyond the helpers highlighted above, JQ::Lite ships with a wide set of jq compatibility functions for arithmetic, statistics, type inspection, and data manipulation. Highlights include:

  • Numeric helpers: add, sum, product, min, max, avg, median, percentile, variance, stddev, clamp

  • Array utilities: first, last, reverse, drop, tail, chunks, range, transpose, flatten_all, flatten_depth, enumerate

  • Object introspection: keys, keys_unsorted, values, has, contains, to_entries, from_entries, with_entries, map_values, pick, merge_objects, paths, leaf_paths, getpath, setpath, del, delpaths

  • Type and string tools: type, tostring, tojson, fromjson, to_number, upper, lower, titlecase, trim, ltrimstr, rtrimstr, substr, slice, startswith, endswith, test, split, join, explode, implode

  • Boolean logic and predicates: not, any, all, walk, map, select, indices, index, rindex, arrays, objects, scalars

Run jq-lite --help-functions to view the exhaustive list directly from the executable.

SEE ALSO

jq, JSON::PP, JSON::XS, Cpanel::JSON::XS, JSON::MaybeXS

AUTHOR

Kawamura Shingo <pannakoota1\@gmail.com>

LICENSE

Same as Perl itself.