NAME

JSON::Relaxed -- An extension of JSON that allows for better human-readability

Relaxed JSON?

There's been increasing support for the idea of expanding JSON to improve human-readability. "Relaxed" JSON (RJSON) is a term that has been used to describe a JSON-ish format that has some human-friendly features that JSON doesn't. Most notably, RJSON allows the use of JavaScript-like comments and eliminates the need to quote all keys and values. An (official) specification can be found on RelaxedJSON.org.

Note that by definition every valid JSON document is also a valid RJSON document.

SYNOPSIS

use JSON::Relaxed;

# Some raw RJSON data.
my $rjson = <<'RAW_DATA';
/* Javascript-like comments. */
{
    // Keys do not require quotes.
    // Single, double and backtick quotes.
    a : 'Larry',
    b : "Curly",
    c : `Phoey`,
    // Simple values do not require quotes.
    d:  unquoted

    // Nested structures.
    e: [
      { a:1, b:2 },
    ],

    // Like Perl, trailing commas are allowed.
    f: "more stuff",
}
RAW_DATA

# Functional parsing.
my $hash = decode_rjson($rjson);

# Object-oriented parsing.
my $parser = JSON::Relaxed->new();
$hash = $parser->decode($rjson);

DESCRIPTION

JSON::Relaxed is a lightweight parser and serializer for RJSON. It is fully compliant to the RelaxedJSON.org specification.

It does, however, have some additional extensions to make it really relaxed.

LEGACY MODE

The old static method from_rjson has been renamed to decode_rjson, to conform to many other modules of this kind. For compatibility with pre-0.060 versions from_rjson is kept as a synonym for decode_rjson.

For the same reason, the old parser method parse has been renamed to decode. For compatibility parse is kept as a synonym for decode.

When called by one of the old names, JSON::Relaxed will operate in legacy mode. This changes the way errors are handled.

REALLY RELAXED EXTENSIONS

Extensions are disabled if option strict is set. Otherwise, most extensions are enabled by default. Some extensions need an additional option setting.

Leading commas in lists

For example,

[ , 1 ]

Enabled by default, overruled by strict.

Hash keys without values

JSON::Relaxed supports object keys without a specified value. In that case the hash element is simply assigned the undefined value.

In the following example, a is assigned 1, and b is assigned undef:

{ a:1, b }

Enabled by default, overruled by strict.

String continuation

Long strings can be aesthetically split over multiple lines by putting a backslash at the end of the line:

"this is a " \
"long string"

Note that this is different from

  "this is a \
long string"

which embeds the newline into the string, and requires continuation lines to start at the beginning of the line to prevent unwanted spaces.

Enabled by default, overruled by strict.

Extended Unicode escapes

Unicode escapes in strings may contain an arbitrary number of hexadecimal digits enclosed in braces:

\u{1d10e}

This eliminates the need to use surrogates to obtain the same character:

\uD834\uDD0E

Enabled by default, overruled by strict.

Combined hash keys

Hash keys that contain periods are considered subkeys, e.g.

foo.bar: blech

is equivalent to

foo: {
    bar: blech
}

Requires combined_keys or prp option. Overruled by strict.

Implied outer hash

If the JSON looks like a hash, i.e. a string (key) followed by a :, the outer { and } are implied.

For example:

foo : bar

is equivalent to:

{ foo : bar }

Requires implied_outer_hash or prp option. Overruled by strict.

Garbage after JSON structure

Requires extra_tokens_ok option. Overruled by strict.

Normally, parsing will fail unless the input contains exactly one valid JSON structure, i.e. a string, a hash or an array.

With extra_tokens_ok the first JSON structure is parsed and the rest is ignored.

PRP extensions

Requires prp option. Overruled by strict.

Enables some specific extensions:

The equal sign = can be used as an alternative to : (colon).

Colon (and equal sign) is optional between a key and its hash value.

Single-line comments may start with #.

For example:

# This is a sample PRP extended Really Relaxed JSON.
pdf.formats {
  title.footer = [ "%{copyright}" "" "%{page}" ]
  first.footer = [ "%{copyright}" "" "" ]
}

This is equivalent to Really Relaxed JSON:

// This is a sample Really Relaxed JSON.
pdf.formats: {
  title.footer: [ "%{copyright}" "" "%{page}" ]
  first.footer: [ "%{copyright}" "" "" ]
}

And Relaxed JSON:

// This is a sample Relaxed JSON.
{
  pdf: {
    formats: {
      title: {
        footer: [ "%{copyright}" "" "%{page}" ]
      }
      first: {
        footer: [ "%{copyright}" "" "" ]
      }
    }
  }
}

And JSON:

{
  "pdf" : {
    "formats" : {
      "title" : {
        "footer" : [ "%{copyright}", "", "%{page}" ]
      }
    },
    "first" : {
      "footer" : [ "%{copyright}", "", "" ]
      }
    }
  }
}

You decide what is easiest to write ☺.

SUBROUTINES

decode_rjson

$structure = decode_rjson( $data, %options )

decode_rjson() is the simple way to parse an RJSON string. It is exported by default. decode_rjson takes a single parameter, the string to be parsed.

Optionally an additional hash with options can be passed to change the behaviour of the parser. See below.

$structure = decode_rjson( $rjson, %options );

OBJECT-ORIENTED PARSING

new

Create a JSON::Relaxed object, suitable for one or many operations.

$parser = JSON::Relaxed->new( %options );

Options:

strict

When set to a true value, enforces full compliance with the RelaxedJSON.org specification.

Default value is false, enabling JSON::Relaxed extensions.

croak_on_error

Disabled by default in legacy mode, enabled otherwise.

Causes parsing error to be signalled with an exception.

See "ERROR HANDLING".

extra_tokens_ok
combined_keys
implied_outer_hash
prp

Enables/disables some of the extensions described above.

key_order

Adds a key " key order " to each hash, containing an array with the hash keys in order of appearance. This is used for pretty printing.

decode

This method parses the JSON string, passed as argument.

$structure = $parser->decode($rjson);

parse

This is the same as decode, but also enables legacy mode.

err_id

err_pos

err_msg

Fetches the error information for the last error, if any.

Error ids are simple short strings, like "multiple-structures".

err_pos fetches the text position in the JSON string where the error occured. Returns -1 if this information is not available.

err_msg Fetches the text of the last error message.

For a full list, see JSON::Relaxed::ErrorCodes.

strict

croak_on_error

extra_tokens_ok

combined_keys

implied_outer_hash

prp

pretty (see "encode")

key_order

booleans (see "Boolean values")

Sets/resets options.

Note that the value must be assigned to, e.g.

$parser->strict = 1;	# enable

encode

$string = $parser->encode( data => $data, %options )

Produces a string with a really relaxed rendition of the data. With option pretty, the rendition is pretty-printed.

With option key_order the order of hash keys will be taken from a pseudo-key " key order ". This pseudo-key is added when option key_order is passed to decode.

A Perl structure is passed as data option. This structure is encoded. Note however that this structure may contain only strings, arrays and hashes.

Option schema can be used to provide schema data for structure to be encoded. For each item to be encoded, the schema is consulted and the following schema items are prepended as comments: title, description, and infoText.

MAPPING

RRJSON to Perl

  • Numbers are unquoted strings. They will be mapped to numbers if the repesentation is identical to the source. For example, the unquoted string 1 and the quoted string "1" will both yield the number 1 The unquoted string 1.0 will also yield the number 1, but "1.0" will yield the string "1.0".

  • Unquoted null will become undef.

  • Unquoted true and false will yield JSON::Boolean objects that test as boolean (true resp. false) and stringify as "true" resp. "false". See "Boolean values" how to change this behaviour.

    Likewise unquoted on and off when option prp is specified.

  • Other unquoted strings will be treated as quoted strings.

Perl to RRJSON

  • Numbers will be output as numbers.

  • Strings will be output as unquoted strings if possible, quoted strings otherwise. Non-latin characters will be output as \u escapes. When some of the quotes " ' ` are embedded the others will be tried for the string, e.g. "a\"b" will yield 'a"b'.

    All quotes are equal, there is no difference in interpretation.

  • Boolean objects will be output as unquoted true and false.

  • Undefined values will be output as null.

Boolean values

By default JSON::Boolean objects will be used for unquoted true and false. The booleans method can be used to change this.

$parser->booleans = [ false-value, true-value ]

This sets the values to be used for true and false. Default is

$parser->booleans = [ $JSON::Boolean::false, $JSON::Boolean::true  ]

A non-array true value establishes the default.

Setting to a false value is the same as

$parser->booleans = [ 0, 1 ]

With option prp, unquoted on is the same as true, and off is the same as false.

ERROR HANDLING

If the document cannot be parsed, JSON::Relaxed will throw an exception.

In legacy mode, JSON::Relaxed returns an undefined value and sets error indicators in $JSON::Relaxed::err_id and $JSON::Relaxed::err_msg.

If parser property croak_on_error is set to a false value, it will behave as if in legacy mode.

For a full list of error codes, see JSON::Relaxed::ErrorCodes.

AUTHOR

Johan Vromans jv@cpan.org

Based on original code from Miko O'Sullivan miko@idocs.com.

SUPPORT

Development of this module takes place on GitHub: https://github.com/sciurius/perl-JSON-Relaxed.

You can find documentation for this module with the perldoc command.

perldoc JSON::Relaxed

Please report any bugs or feature requests using the issue tracker on GitHub.

LICENSE

Copyright (c) 2024 by Johan Vromans. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. This software comes with NO WARRANTY of any kind.