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(.key1 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
elifclauses cascade additional tests, and the optionalelsefilter runs only when no prior branch matched. When noelseclause 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" endreduce 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_descReturns:
[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
explodehelper and pairs withimplodefor round-trip transformations.Example:
.title | explodeReturns:
[67, 79, 68, 69]implode()Perform the inverse of
explodeby turning arrays of Unicode code points back into strings. Nested arrays are processed recursively so pipelines likeexplode | implodework over heterogeneous structures. Non-array inputs pass through unchanged.Example:
.codes | implodeReturns:
"CODE"keys_unsorted()Returns the keys of an object without sorting them, mirroring jq's
keys_unsortedhelper. Arrays yield their zero-based indices, while non-object/array inputs returnundefto match the behaviour ofkeys.Example:
.profile | keys_unsortedvalues()Returns all values of a hash as an array. Example:
.profile | valuespaths()Enumerates every path within the current value, mirroring jq's
pathshelper. 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 | pathsReturns:
[["name"], ["tags"], ["tags",0], ["tags",1], ["active"]]leaf_paths()Enumerates only the paths that terminate in non-container values, mirroring jq's
leaf_pathshelper. This is equivalent topaths(scalars)in jq.Example:
.user | leaf_pathsReturns:
[["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 aspaths()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/2semantics. 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
keyandvaluefields 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_entriesfrom_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_entrieswith_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 asmap_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,clampArray utilities:
first,last,reverse,drop,tail,chunks,range,transpose,flatten_all,flatten_depth,enumerateObject introspection:
keys,keys_unsorted,values,has,contains,to_entries,from_entries,with_entries,map_values,pick,merge_objects,paths,leaf_paths,getpath,setpath,del,delpathsType and string tools:
type,tostring,tojson,fromjson,to_number,upper,lower,titlecase,trim,ltrimstr,rtrimstr,substr,slice,startswith,endswith,test,split,join,explode,implodeBoolean 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.