NAME
JQ::Lite - A lightweight jq-like JSON query engine in Perl
VERSION
Version 0.62
SYNOPSIS
use JQ::Lite;
my $jq = JQ::Lite->new;
my @results = $jq->run_query($json_text, '.users[].name');
for my $r (@results) {
print encode_json($r), "\n";
}
DESCRIPTION
JQ::Lite is a lightweight, pure-Perl JSON query engine inspired by the jq command-line tool.
It allows you to extract, traverse, and filter JSON data using a simplified jq-like syntax — entirely within Perl, with no external binaries or XS modules.
FEATURES
Pure Perl (no XS, no external binaries required)
Dot notation traversal (e.g. .users[].name)
Optional key access using '?' (e.g. .nickname?)
Array indexing and flattening (.users[0], .users[])
Boolean filters via select(...) with ==, !=, <, >, and, or
Pipe-style query chaining using | operator
Built-in functions: length, keys, values, first, last, reverse, sort, sort_desc, sort_by, unique, unique_by, has, contains, group_by, group_count, join, split, count, empty, type, nth, del, compact, upper, lower, abs, ceil, floor, trim, substr, startswith, endswith, add, sum, product, min, max, avg, median, stddev, drop, chunks
Supports map(...), limit(n), drop(n), and chunks(n) style transformations
Interactive mode for exploring queries line-by-line
Command-line interface:
jq-lite
(compatible with stdin or file)Decoder selection via
--use
(JSON::PP, JSON::XS, etc.)Debug output via
--debug
List all functions with
--help-functions
CONSTRUCTOR
new
my $jq = JQ::Lite->new;
Creates a new instance. 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.
SUPPORTED SYNTAX
.key.subkey
.array[0] (index access)
.array[] (flattening arrays)
.key? (optional key access)
select(.key > 1 and .key2 == "foo") (boolean filters)
group_by(.field) (group array items by key)
group_count(.field) (tally items by key)
sort_desc()
Sort array elements in descending order using smart numeric/string comparison.
Example:
.scores | sort_desc
Returns:
[100, 75, 42, 12]
sort_by(.key) (sort array of objects by key)
unique_by(.key) (remove duplicates based on a projected key)
.key | count (count items or fields)
.[] | select(...) | count (combine flattening + filter + count)
.array | map(.field) | join(", ")
Concatenates 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"]
values()
Returns all values of a hash as an array. Example:
.profile | values
empty()
Discards all output. Compatible with jq. Useful when only side effects or filtering is needed without output.
Example:
.users[] | select(.age > 25) | empty
.[] as alias for flattening top-level arrays
type()
Returns the type of the value as a string: "string", "number", "boolean", "array", "object", or "null".
Example:
.name | type # => "string" .tags | type # => "array" .profile | type # => "object"
nth(n)
Returns the nth element (zero-based) from an array.
Example:
.users | nth(0) # first user .users | nth(2) # third user
del(key)
Deletes a specified key from a hash object and returns a new hash without that key.
Example:
.profile | del("password")
If the key does not exist, returns the original hash unchanged.
If applied to a non-hash object, returns the object unchanged.
compact()
Removes undef and null values from an array.
Example:
.data | compact()
Before: [1, null, 2, null, 3]
After: [1, 2, 3]
upper()
Converts strings to uppercase. When applied to arrays, each scalar element is uppercased recursively, leaving nested hashes or booleans untouched.
Example:
.title | upper # => "HELLO WORLD" .tags | upper # => ["PERL", "JSON"]
lower()
Converts strings to lowercase. When applied to arrays, each scalar element is lowercased recursively, leaving nested hashes or booleans untouched.
Example:
.title | lower # => "hello world" .tags | lower # => ["perl", "json"]
contains(value)
Checks whether the current value includes the supplied fragment.
* For strings, returns true when the substring exists. * For arrays, returns true if any element equals the supplied value. * For hashes, returns true when the key is present.
Example:
.title | contains("perl") # => true .tags | contains("json") # => true .meta | contains("lang") # => true
unique_by(".key")
Removes duplicate objects (or values) from an array by projecting each entry to the supplied key path and keeping only the first occurrence of each signature. Use
.
to deduplicate by the entire value.Example:
.users | unique_by(.name) # => keeps first record for each name .tags | unique_by(.) # => removes duplicate scalars
startswith("prefix")
Returns true if the current string (or each string inside an array) begins with the supplied prefix. Non-string values yield
false
.Example:
.title | startswith("Hello") # => true .tags | startswith("j") # => [false, true, false]
endswith("suffix")
Returns true if the current string (or each string inside an array) ends with the supplied suffix. Non-string values yield
false
.Example:
.title | endswith("World") # => true .tags | endswith("n") # => [false, true, false]
substr(start[, length])
Extracts a substring from the current string using zero-based indexing. When applied to arrays, each scalar element receives the same slicing arguments recursively.
Examples:
.title | substr(0, 5) # => "Hello" .tags | substr(-3) # => ["erl", "SON"]
abs()
Returns absolute values for numbers. Scalars are converted directly, while arrays are processed element-by-element with non-numeric entries preserved.
Example:
.temperature | abs # => 12 .deltas | abs # => [3, 4, 5, "n/a"]
ceil()
Rounds numbers up to the nearest integer. Scalars and array elements that look like numbers are rounded upward, while other values pass through unchanged.
Example:
.price | ceil # => 20 .changes | ceil # => [2, -1, "n/a"]
floor()
Rounds numbers down to the nearest integer. Scalars and array elements that look like numbers are rounded downward, leaving non-numeric values untouched.
Example:
.price | floor # => 19 .changes | floor # => [1, -2, "n/a"]
round()
Rounds numbers to the nearest integer using standard rounding (half up for positive values, half down for negatives). Scalars and array elements that look like numbers are adjusted, while other values pass through unchanged.
Example:
.price | round # => 19 .changes | round # => [1, -2, "n/a"]
trim()
Removes leading and trailing whitespace from strings. Arrays are processed recursively, while hashes and other references are left untouched.
Example:
.title | trim # => "Hello World" .tags | trim # => ["perl", "json"]
COMMAND LINE USAGE
jq-lite
is a CLI wrapper for this module.
cat data.json | jq-lite '.users[].name'
jq-lite '.users[] | select(.age > 25)' data.json
jq-lite -r '.users[].name' data.json
jq-lite '.[] | select(.active == true) | .name' data.json
jq-lite '.users[] | select(.age > 25) | count' data.json
jq-lite '.users | map(.name) | join(", ")'
jq-lite '.users[] | select(.age > 25) | empty'
jq-lite '.profile | values'
Interactive Mode
Omit the query to enter interactive mode:
jq-lite data.json
You can then type queries line-by-line against the same JSON input.
Decoder Selection and Debug
jq-lite --use JSON::PP --debug '.users[0].name' data.json
Show Supported Functions
jq-lite --help-functions
Displays all built-in functions and their descriptions.
REQUIREMENTS
Uses only core modules:
JSON::PP
Optional: JSON::XS, Cpanel::JSON::XS, JSON::MaybeXS
SEE ALSO
AUTHOR
Kawamura Shingo <pannakoota1@gmail.com>
LICENSE
Same as Perl itself.