Data::Roundtrip - convert between Perl data structures, YAML and JSON with unicode support (I believe ...)
Version 0.14
This module contains a collection of utilities for converting between JSON, YAML, Perl variable and a Perl variable's string representation (aka dump). Hopefully, all unicode content will be handled correctly between the conversions and optionally escaped or un-escaped. Also JSON can be presented in a pretty format or in a condensed, machine-readable format (not spaces, indendation or line breaks).
use Data::Roundtrip qw/:all/; #use Data::Roundtrip qw/json2yaml/; #use Data::Roundtrip qw/:json/; # see EXPORT $jsonstr = '{"Songname": "Απόκληρος της κοινωνίας",' .'"Artist": "Καζαντζίδης Στέλιος/Βίρβος Κώστας"}' ; $yamlstr = json2yaml($jsonstr); print $yamlstr; # NOTE: long strings have been broken into multilines # and/or truncated (replaced with ...) #--- #Artist: Καζαντζίδης Στέλιος/Βίρβος Κώστας #Songname: Απόκληρος της κοινωνίας $yamlstr = json2yaml($jsonstr, {'escape-unicode'=>1}); print $yamlstr; #--- #Artist: \u039a\u03b1\u03b6\u03b1 ... #Songname: \u0391\u03c0\u03cc\u03ba ... $backtojson = yaml2json($yamlstr); # $backtojson is a string representation # of following JSON structure: # {"Artist":"Καζαντζίδης Στέλιος/Βίρβος Κώστας", # "Songname":"Απόκληρος της κοινωνίας"} # This is useful when sending JSON via # a POST request and it needs unicode escaped: $backtojson = yaml2json($yamlstr, {'escape-unicode'=>1}); # $backtojson is a string representation # of following JSON structure: # but this time with unicode escaped # (pod content truncated for readbility) # {"Artist":"\u039a\u03b1\u03b6 ...", # "Songname":"\u0391\u03c0\u03cc ..."} # this is the usual Data::Dumper dump: print json2dump($jsonstr); #$VAR1 = { # 'Songname' => "\x{391}\x{3c0}\x{3cc} ...", # 'Artist' => "\x{39a}\x{3b1}\x{3b6} ...", #}; # and this is a more human-readable version: print json2dump($jsonstr, {'dont-bloody-escape-unicode'=>1}); # $VAR1 = { # "Artist" => "Καζαντζίδης Στέλιος/Βίρβος Κώστας", # "Songname" => "Απόκληρος της κοινωνίας" # }; # pass some parameters to Data::Dumper # like: be terse (no $VAR1): print json2dump($jsonstr, {'dont-bloody-escape-unicode'=>0, 'terse'=>1} #{'dont-bloody-escape-unicode'=>0, 'terse'=>1, 'indent'=>0} ); # { # "Artist" => "Καζαντζίδης Στέλιος/Βίρβος Κώστας", # "Songname" => "Απόκληρος της κοινωνίας" # } # this is how to reformat a JSON string to # have its unicode content escaped: my $json_with_unicode_escaped = json2json($jsonstr, {'escape-unicode'=>1}); # For some of the above functions there exist command-line scripts: perl2json.pl -i "perl-data-structure.pl" -o "output.json" --pretty json2json.pl -i "with-unicode.json" -o "unicode-escaped.json" --escape-unicode # etc. # only for *2dump: perl2dump, json2dump, yaml2dump # and if no escape-unicode is required (i.e. # setting 'dont-bloody-escape-unicode' => 1 permanently) # and if efficiency is important, # meaning that perl2dump is run in a loop thousand of times, # then import the module like this: use Data::Roundtrip qw/:all no-unicode-escape-permanently/; # or like this use Data::Roundtrip qw/:all unicode-escape-permanently/; # then perl2dump() is more efficient but unicode characters # will be permanently not-escaped (1st case) or escaped (2nd case).
By default no symbols are exported. However, the following export tags are available (:all will export all of them):
:json : perl2json(), json2perl(), json2dump(), json2yaml(), json2json()
:json
perl2json()
json2perl()
json2dump()
json2yaml()
json2json()
:yaml : perl2yaml(), yaml2perl(), yaml2dump(), yaml2yaml(), yaml2json()
:yaml
perl2yaml()
yaml2perl()
yaml2dump()
yaml2yaml()
yaml2json()
:dump : perl2dump(), perl2dump_filtered(), perl2dump_homebrew(), dump2perl(), dump2json(), dump2yaml()
:dump
perl2dump()
perl2dump_filtered()
perl2dump_homebrew()
dump2perl()
dump2json()
dump2yaml()
:io : read_from_file(), write_to_file(), read_from_filehandle(), write_to_filehandle(),
:io
read_from_file()
write_to_file()
read_from_filehandle()
write_to_filehandle()
:all : everything above
:all
no-unicode-escape-permanently : this is not an export keyword/parameter but a parameter which affects all the *2dump* subs by setting unicode escaping permanently to false. See "EFFICIENCY".
no-unicode-escape-permanently
*2dump*
unicode-escape-permanently : this is not an export keyword/parameter but a parameter which affects all the *2dump* subs by setting unicode escaping permanently to true. See "EFFICIENCY".
unicode-escape-permanently
The export keyword/parameter no-unicode-escape-permanently affects all the *2dump* subs by setting unicode escaping permanently to false. This improves efficiency, although one will ever need to use this in extreme situations where a *2dump* sub is called repeatedly in a loop of a few hundreds or thousands of iterations or more.
Each time a *2dump* is called, the dont-bloody-escape-unicode flag is checked and if it is set, then Data::Dumper's qquote() is overriden with _qquote_redefinition_by_Corion() just for that instance and will be restored as soon as the dump is finished. Similarly, a filter for not escaping unicode is added to Data::Dump just for that particular call and is removed immediately after. This has some computational cost and can be avoided completely by overriding the sub and adding the filter once, at loading (in import()).
dont-bloody-escape-unicode
qquote()
_qquote_redefinition_by_Corion()
import()
The price to pay for this added efficiency is that unicode in any dump will never be escaped (e.g. \x{3b1}), but will be rendered (e.g. α, a greek alpha). Always. The option dont-bloody-escape-unicode will permanently be set to true.
\x{3b1})
α
Similarly, the export keyword/parameter unicode-escape-permanently affects all the *2dump* subs by setting unicode escaping permanently to true. This improves efficiency as well.
See "BENCHMARKS" on how to find the fastest *2dump* sub.
The special Makefile target benchmarks will time calls to each of the *2dump* subs under
benchmarks
use Data::Roundtrip; use Data::Roundtrip qw/no-unicode-escape-permanently/; use Data::Roundtrip qw/unicode-escape-permanently/;
and for 'dont-bloody-escape-unicode' => 0 and 'dont-bloody-escape-unicode' => 1.
'dont-bloody-escape-unicode' => 0
'dont-bloody-escape-unicode' => 1
In general, "perl2dump" is faster by 25% when one of the permanent import parameters is used (either of the last two cases above).
perl2json
my $ret = perl2json($perlvar, $optional_paramshashref)
Arguments:
$perlvar
$optional_paramshashref
Return value:
$ret
Given an input $perlvar (which can be a simple scalar or a nested data structure, but not an object), it will return the equivalent JSON string. In $optional_paramshashref one can specify whether to escape unicode with 'escape-unicode' => 1 and/or prettify the returned result with 'pretty' => 1. The output can be fed back to "json2perl" for getting the Perl variable back.
'escape-unicode' => 1
'pretty' => 1
Returns the JSON string on success or undef on failure.
undef
json2perl
$jsonstring
Given an input $jsonstring as a string, it will return the equivalent Perl data structure using JSON::decode_json(Encode::encode_utf8($jsonstring)).
JSON::decode_json(Encode::encode_utf8($jsonstring))
Returns the Perl data structure on success or undef on failure.
perl2yaml
my $ret = perl2yaml($perlvar, $optional_paramshashref)
Given an input $perlvar (which can be a simple scalar or a nested data structure, but not an object), it will return the equivalent YAML string. In $optional_paramshashref one can specify whether to escape unicode with 'escape-unicode' => 1. Prettify is not supported yet. The output can fed to "yaml2perl" for getting the Perl variable back.
Returns the YAML string on success or undef on failure.
yaml2perl
my $ret = yaml2perl($yamlstring);
$yamlstring
Given an input $yamlstring as a string, it will return the equivalent Perl data structure using YAML::Load($yamlstring)
YAML::Load($yamlstring)
perl2dump
my $ret = perl2dump($perlvar, $optional_paramshashref)
Given an input $perlvar (which can be a simple scalar or a nested data structure, but not an object), it will return the equivalent string (via Data::Dumper). In $optional_paramshashref one can specify whether to escape unicode with 'dont-bloody-escape-unicode' => 0, (or 'escape-unicode' => 1). The DEFAULT behaviour is to NOT ESCAPE unicode.
Additionally, use terse output with 'terse' => 1 and remove all the incessant indentation with 'indent' => 1 which unfortunately goes to the other extreme of producing a space-less output, not fit for human consumption. The output can fed to "dump2perl" for getting the Perl variable back.
'terse' => 1
'indent' => 1
It returns the string representation of the input perl variable on success or undef on failure.
The output can be fed back to "dump2perl".
CAVEAT: when not escaping unicode (which is the default behaviour), each call to this sub will override Data::Dumper's qquote() sub then call Data::Dumper's Dumper() and save its output to a temporary variable, restore qquote() sub to its original code ref and return the contents. This exercise is done every time this perl2dump() is called. It may be expensive. The alternative is to redefine qquote() once, when the module is loaded, with all the side-effects this may cause.
Dumper()
Note that there are two other alternative subs which offer more-or-less the same functionality and their output can be fed back to all the dump2*() subs. These are "perl2dump_filtered" which uses Data::Dump::Filtered to add a filter to control unicode escaping but lacks in aesthetics and functionality and handling all the cases Dump and Dumper do quite well.
dump2*()
There is also perl2dump_homebrew() which uses the same dump-recursively engine as "perl2dump_filtered" but does not involve Data::Dump at all.
perl2dump_filtered
my $ret = perl2dump_filtered($perlvar, $optional_paramshashref)
It does the same job as "perl2dump" which is to stringify a perl variable. And takes the same options.
It uses Data::Dump::Filtered to add a filter to Data::Dump.
head3 CAVEAT
In order to xxx
perl2dump_homebrew
my $ret = perl2dump_homebrew($perlvar, $optional_paramshashref)
It uses its own basic dumper. Which is recursive. So, beware of extremely deep nested data structures. Deep not long! But it probably is as efficient as it can be but definetely lacks in aesthetics and functionality compared to Dump and Dumper.
dump_perl_var_recursively
my $ret = dump_perl_var_recursively($perl_var)
$perl_var, a Perl variable like a scalar or an arbitrarily nested data structure. For the latter, it requires references, e.g. hash-ref or arrayref.
$perl_var
$ret, the stringified version of the input Perl variable.
This sub will take a Perl var (as a scalar or an arbitrarily nested data structure) and emulate a very very basic Dump/Dumper but with enforced rendering unicode (for keys or values or array items), and not escaping unicode - this is not an option, it returns a string representation of the input perl var
There are 2 obvious limitations:
Data::Dump::Filtered::add_dump_filter( \& DataDumpFilterino ); or dumpf($perl_var, \& DataDumpFilterino);
the input is a Perl variable as a reference, so no %inp but $inp={} and $inp=[].
%inp
$inp={}
$inp=[]
This function is recursive. Beware of extremely deep nested data structures. Deep not long! But it probably is as efficient as it can be but definetely lacks in aesthetics and functionality compared to Dump and Dumper.
The output is a, possibly multiline, string. Which it can then be fed back to "dump2perl".
dump2perl
my $ret = dump2perl($dumpstring)
$dumpstring, this comes from the output of Data::Dump, Data::Dumper or our own "perl2dump", "perl2dump_filtered", "perl2dump_homebrew". Escaped, or unescaped.
$dumpstring
$ret, the Perl data structure on success or undef on failure.
my $ret = json2perl($jsonstring)
In $optional_paramshashref one can specify whether to escape unicode with 'escape-unicode' => 1 and/or prettify the returned result with 'pretty' => 1.
Returns the yaml string on success or undef on failure.
json2yaml
my $ret = json2yaml($jsonstring, $optional_paramshashref)
Given an input JSON string $jsonstring, it will return the equivalent YAML string YAML by first converting JSON to a Perl variable and then converting that variable to YAML using "perl2yaml". All the parameters supported by "perl2yaml" are accepted.
yaml2json
my $ret = yaml2json($yamlstring, $optional_paramshashref)
Given an input YAML string $yamlstring, it will return the equivalent YAML string YAML by first converting YAML to a Perl variable and then converting that variable to JSON using "perl2json". All the parameters supported by "perl2json" are accepted.
json2json
yaml2yaml
Transform a json or yaml string via pretty printing or via escaping unicode or via un-escaping unicode. Parameters like above will be accepted.
json2dump
dump2json
yaml2dump
dump2yaml
similar functionality as their counterparts described above.
read_from_file
my $contents = read_from_file($filename)
$filename : the input filename.
$filename
$contents
Given a filename, it opens it using :encoding(UTF-8), slurps its contents and closes it. It's a convenience sub which could have also been private. If you want to retain the filehandle, use "read_from_filehandle".
:encoding(UTF-8)
Returns the file contents on success or undef on failure.
read_from_filehandle
my $contents = read_from_filehandle($filehandle)
$filehandle : the handle to an already opened file.
$filehandle
$contents : the file contents slurped.
It slurps all content from the specified input file handle. Upon return the file handle is still open. Returns the file contents on success or undef on failure.
write_to_file
write_to_file($filename, $contents) or die
$filename : the output filename.
$contents : any string to write it to file.
1 on success, 0 on failure
Given a filename, it opens it using :encoding(UTF-8), writes all specified content and closes the file. It's a convenience sub which could have also been private. If you want to retain the filehandle, use "write_to_filehandle".
Returns 1 on success or 0 on failure.
write_to_filehandle
write_to_filehandle($filehandle, $contents) or die
$filehandle : the handle to an already opened file (for writing).
1 on success or 0 on failure.
It writes content to the specified file handle. Upon return the file handle is still open.
A few scripts have been put together and offer the functionality of this module to the command line. They are part of this distribution and can be found in the script directory.
script
These are: json2json.pl, json2yaml.pl, yaml2json.pl, json2perl.pl, perl2json.pl, yaml2perl.pl
json2json.pl
json2yaml.pl
yaml2json.pl
json2perl.pl
perl2json.pl
yaml2perl.pl
A valid Perl variable may kill YAML::Load because of escapes and quotes. For example this:
my $yamlstr = <<'EOS'; --- - 682224 - "\"w": 1 EOS my $pv = eval { YAML::Load($yamlstr) }; if( $@ ){ die "failed(1): ". $@ } # it's dead
Strangely, there is no problem for this:
my $yamlstr = <<'EOS'; --- - 682224 - "\"w" EOS # this is OK also: # - \"w: 1 my $pv = eval { YAML::Load($yamlstr) }; if( $@ ){ die "failed(1): ". $@ } # it's OK! still alive.
Andreas Hadjiprocopis, <bliako at cpan.org> / <andreashad2 at gmail.com>
<bliako at cpan.org> / <andreashad2 at gmail.com>
Please report any bugs or feature requests to bug-data-roundtrip at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Data-Roundtrip. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
bug-data-roundtrip at rt.cpan.org
You can find documentation for this module with the perldoc command.
perldoc Data::Roundtrip
You can also look for information at:
RT: CPAN's request tracker (report bugs here)
https://rt.cpan.org/NoAuth/Bugs.html?Dist=Data-Roundtrip
AnnoCPAN: Annotated CPAN documentation
http://annocpan.org/dist/Data-Roundtrip
CPAN Ratings
https://cpanratings.perl.org/d/Data-Roundtrip
Search CPAN
https://metacpan.org/release/Data-Roundtrip
Several Monks at PerlMonks.org (in no particular order):
Almaz!
This software, EXCEPT the portions created by [Corion] @ Perlmonks and [kcott] @ Perlmonks, is Copyright (c) 2020 by Andreas Hadjiprocopis.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
To install Data::Roundtrip, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Data::Roundtrip
CPAN shell
perl -MCPAN -e shell install Data::Roundtrip
For more information on module installation, please visit the detailed CPAN module installation guide.