JSON::Transform - arbitrary transformation of JSON-able data
use JSON::Transform qw(parse_transform); use JSON::MaybeXS; my $transformer = parse_transform(from_file($transformfile)); to_file($outputfile, encode_json $transformer->(decode_json $json_input));
Implements a language concisely describing a set of transformations from an arbitrary JSON-able piece of data, to another one. The description language uses JSON Pointer (RFC 6901) for addressing. JSON-able means only strings, booleans, nulls (Perl undef), numbers, array-refs, hash-refs, with no circular references.
undef
A transformation is made up of an output expression, which can be composed of sub-expressions.
For instance, to transform an array of hashes that each have an id key, to a hash mapping each id to its hash:
id
# [ { "id": 1, "name": "Alice" }, { "id": 2, "name": "Bob" } ] # -> "" <@ { "/$K/id":$V#`id` } # -> # { "1": { "name": "Alice" }, "2": { "name": "Bob" } }
While to do the reverse transformation:
"" <% [ $V@`id`:$K ]
The identity for an array:
"" <@ [ $V ]
The identity for an object/hash:
"" <% { $K:$V }
To get the keys of a hash:
"" <% [ $K ]
To get how many keys in a hash:
"" <% $C
To get how many items in an array:
"" <@ $C
To move from one part of a structure to another:
"/destination" << "/source"
To copy from one part of a structure to another:
"/destination" <- "/source"
To do the same with a transformation (assumes /source is an array of hashes):
/source
"/destination" <- "/source" <@ [ $V@`order`:$K ]
To bind a variable, then replace the whole data structure:
$defs <- "/definitions" "" <- $defs
A slightly complex transformation, using the jt script:
$ cat <<EOF | jt '"" <- "/Time Series (Daily)" <% [ .{ `date`: $K, `close`: $V<"/4. close" } ]' { "Meta Data": {}, "Time Series (Daily)": { "2018-10-26": { "1. open": "", "4. close": "106.9600" }, "2018-10-25": { "1. open": "", "4. close": "108.3000" } } } EOF # produces: [ {"date":"2018-10-25","close":"108.3000"}, {"date":"2018-10-26","close":"106.9600"} ]
These terms are used here interchangeably.
JSON pointers are surrounded by "". JSON pointer syntax gives special meaning to the ~ character, as well as to /. To quote a ~, say ~0. To quote a /, say ~1. Since a $ has special meaning, to use a literal one, quote it with a preceding \.
""
~
/
~0
~1
$
\
The output type of a JSON pointer is whatever the pointed-at value is.
A transformation has a destination, a transformation type operator, and a source-value expression. The destination can be a variable to bind to, or a JSON pointer.
If the source-value expression has a JSON-pointer source, then the destination can be omitted and the JSON-pointer source will be used.
The output type of the source-value expression can be anything.
<-
Copying (including assignment for variable bindings)
<<
Moving - error if the source-value is other than a bare JSON pointer
These can be either a variable, or a JSON pointer.
These are expressed as $ followed by a lower-case letter, followed by zero or more letters.
These can be either a single value including variables, of any type, or a mapping expression.
String value expressions can be surrounded by ``. They have the same quoting rules as in JSON's "-surrounded strings, including quoting of ` using \. Any value inside, including variables, will be concatenated in the obvious way, and numbers will be coerced into strings (be careful of locale). Booleans and nulls will be stringified into [true], [false], [null].
``
"
`
[true]
[false]
[null]
These are a single value of type array, expressed as surrounded by .[], with zero or more comma-separated single values.
.[]
These are a single value of type object/hash, expressed as surrounded by .{}, with zero or more comma-separated colon pairs (see "Mapping to an object/hash", below).
.{}
A mapping expression has a source-value, a mapping operator, and a mapping description.
The mapping operator is either <@, requiring the source-value to be of type array, or <%, requiring type object/hash. If the input data pointed at by the source value expression is not the right type, this is an error.
<@
<%
The mapping description must be surrounded by either [] meaning return type array, or {} for object/hash.
[]
{}
The description will be evaluated once for each input value. Within the brackets, $K and $V will have special meaning.
$K
$V
For an array input, each input will be each single array value, and $K will be the zero-based array index.
For an object/hash input, each input will be each pair. $K will be the object key being evaluated, of type string.
In either case, $V will be the relevant value, of whatever type from the input. $C will be of type integer, being the number of inputs.
$C
The return value will be of type object/hash, composed of a set of pairs, expressed within {} as:
:
Within [], the value expression will be an arbitrary value expression.
A single value can have a modifier, followed by arguments.
@
The operand value must be of type object/hash. The argument must be a pair of string-value, :, any-value. The return value will be the object/hash with that additional key/value pair.
#
The operand value must be of type object/hash. The argument must be a string-value. The return value will be the object/hash without that key.
<
The operand value must be of type object/hash or array. The argument must be a JSON pointer. The return value will be the value, but having had the JSON pointer applied.
Available in mapping expressions. For each data pair, set to either the zero-based index in an array, or the string key of an object/hash.
Available in mapping expressions. For each data pair, set to the value.
Available in mapping expressions. Set to the integer number of values.
Any -- sequence up to the end of that line will be a comment, and ignored.
--
To debug, set environment variable JSON_TRANSFORM_DEBUG to a true value.
JSON_TRANSFORM_DEBUG
On error, throws an exception. On success, returns a function that can be called with JSON-able data, that will either throw an exception or return the transformed data.
Takes arguments:
The text describing the transformation.
Pegex
RFC 6902 - JSON Patch - intended to change an existing structure, leaving it (largely) the same shape
Ed J, <etj at cpan.org>
<etj at cpan.org>
Please report any bugs or feature requests on https://github.com/mohawk2/json-transform/issues.
Or, if you prefer email and/or RT: to bug-json-transform at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=JSON-Transform. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
bug-json-transform at rt.cpan.org
Copyright 2018 Ed J.
This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:
http://www.perlfoundation.org/artistic_license_2_0
To install JSON::Transform, copy and paste the appropriate command in to your terminal.
cpanm
cpanm JSON::Transform
CPAN shell
perl -MCPAN -e shell install JSON::Transform
For more information on module installation, please visit the detailed CPAN module installation guide.