1#!/opt/bin/perl 2 3=head1 NAME 4 5json_xs - JSON::XS commandline utility 6 7=head1 SYNOPSIS 8 9 json_xs [-v] [-f inputformat] [-t outputformat] 10 11=head1 DESCRIPTION 12 13F<json_xs> converts between some input and output formats (one of them is 14JSON). 15 16The default input format is C<json> and the default output format is 17C<json-pretty>. 18 19=head1 OPTIONS 20 21=over 4 22 23=item -v 24 25Be slightly more verbose. 26 27=item -f fromformat 28 29Read a file in the given format from STDIN. 30 31C<fromformat> can be one of: 32 33=over 4 34 35=item json - a json text encoded, either utf-8, utf16-be/le, utf32-be/le 36 37=item cbor - CBOR (RFC 7049, L<CBOR::XS>), a kind of binary JSON 38 39=item storable - a L<Storable> frozen value 40 41=item storable-file - a L<Storable> file (Storable has two incompatible formats) 42 43=item bencode - use L<Convert::Bencode>, if available (used by torrent files, among others) 44 45=item clzf - L<Compress::LZF> format (requires that module to be installed) 46 47=item eval - evaluate the given code as (non-utf-8) Perl, basically the reverse of "-t dump" 48 49=item yaml - L<YAML> (avoid at all costs, requires the YAML module :) 50 51=item string - do not attempt to decode the file data 52 53=item none - nothing is read, creates an C<undef> scalar - mainly useful with C<-e> 54 55=back 56 57=item -t toformat 58 59Write the file in the given format to STDOUT. 60 61C<toformat> can be one of: 62 63=over 4 64 65=item json, json-utf-8 - json, utf-8 encoded 66 67=item json-pretty - as above, but pretty-printed 68 69=item json-utf-16le, json-utf-16be - little endian/big endian utf-16 70 71=item json-utf-32le, json-utf-32be - little endian/big endian utf-32 72 73=item cbor - CBOR (RFC 7049, L<CBOR::XS>), a kind of binary JSON 74 75=item storable - a L<Storable> frozen value in network format 76 77=item storable-file - a L<Storable> file in network format (Storable has two incompatible formats) 78 79=item bencode - use L<Convert::Bencode>, if available (used by torrent files, among others) 80 81=item clzf - L<Compress::LZF> format 82 83=item yaml - L<YAML> 84 85=item dump - L<Data::Dump> 86 87=item dumper - L<Data::Dumper> 88 89=item string - writes the data out as if it were a string 90 91=item none - nothing gets written, mainly useful together with C<-e> 92 93Note that Data::Dumper doesn't handle self-referential data structures 94correctly - use "dump" instead. 95 96=back 97 98=item -e code 99 100Evaluate perl code after reading the data and before writing it out again 101- can be used to filter, create or extract data. The data that has been 102written is in C<$_>, and whatever is in there is written out afterwards. 103 104=back 105 106=head1 EXAMPLES 107 108 json_xs -t none <isitreally.json 109 110"JSON Lint" - tries to parse the file F<isitreally.json> as JSON - if it 111is valid JSON, the command outputs nothing, otherwise it will print an 112error message and exit with non-zero exit status. 113 114 <src.json json_xs >pretty.json 115 116Prettify the JSON file F<src.json> to F<dst.json>. 117 118 json_xs -f storable-file <file 119 120Read the serialised Storable file F<file> and print a human-readable JSON 121version of it to STDOUT. 122 123 json_xs -f storable-file -t yaml <file 124 125Same as above, but write YAML instead (not using JSON at all :) 126 127 json_xs -f none -e '$_ = [1, 2, 3]' 128 129Dump the perl array as UTF-8 encoded JSON text. 130 131 <torrentfile json_xs -f bencode -e '$_ = join "\n", map @$_, @{$_->{"announce-list"}}' -t string 132 133Print the tracker list inside a torrent file. 134 135 lwp-request http://cpantesters.perl.org/show/JSON-XS.json | json_xs 136 137Fetch the cpan-testers result summary C<JSON::XS> and pretty-print it. 138 139=head1 AUTHOR 140 141Copyright (C) 2008 Marc Lehmann <json@schmorp.de> 142 143=cut 144 145use strict; 146 147use Getopt::Long; 148use Storable (); 149use Encode; 150 151use JSON::XS; 152 153my $opt_verbose; 154my $opt_from = "json"; 155my $opt_to = "json-pretty"; 156my $opt_eval; 157 158Getopt::Long::Configure ("bundling", "no_ignore_case", "require_order"); 159 160GetOptions( 161 "v" => \$opt_verbose, 162 "f=s" => \$opt_from, 163 "t=s" => \$opt_to, 164 "e=s" => \$opt_eval, 165) or die "Usage: $0 [-v] -f fromformat [-e code] [-t toformat]\n"; 166 167my %F = ( 168 "none" => sub { undef }, 169 "string" => sub { $_ }, 170 "json" => sub { 171 my $enc = 172 /^\x00\x00\x00/s ? "utf-32be" 173 : /^\x00.\x00/s ? "utf-16be" 174 : /^.\x00\x00\x00/s ? "utf-32le" 175 : /^.\x00.\x00/s ? "utf-16le" 176 : "utf-8"; 177 warn "input text encoding is $enc\n" if $opt_verbose; 178 JSON::XS->new->decode (decode $enc, $_) 179 }, 180 "cbor" => sub { require CBOR::XS; CBOR::XS::decode_cbor ($_) }, 181 "storable" => sub { Storable::thaw $_ }, 182 "storable-file" => sub { open my $fh, "<", \$_; Storable::fd_retrieve $fh }, 183 "bencode" => sub { require Convert::Bencode; Convert::Bencode::bdecode ($_) }, 184 "clzf" => sub { require Compress::LZF; Compress::LZF::sthaw ($_) }, 185 "yaml" => sub { require YAML; YAML::Load ($_) }, 186 "eval" => sub { my $v = eval "no strict; no warnings; no utf8;\n#line 1 \"input\"\n$_"; die "$@" if $@; $v }, 187); 188 189my %T = ( 190 "none" => sub { "" }, 191 "string" => sub { $_ }, 192 "json" => sub { encode_json $_ }, 193 "json-utf-8" => sub { encode_json $_ }, 194 "json-pretty" => sub { JSON::XS->new->utf8->pretty->encode ($_) }, 195 "json-utf-16le" => sub { encode "utf-16le", JSON::XS->new->encode ($_) }, 196 "json-utf-16be" => sub { encode "utf-16be", JSON::XS->new->encode ($_) }, 197 "json-utf-32le" => sub { encode "utf-32le", JSON::XS->new->encode ($_) }, 198 "json-utf-32be" => sub { encode "utf-32be", JSON::XS->new->encode ($_) }, 199 "cbor" => sub { require CBOR::XS; CBOR::XS::encode_cbor ($_) }, 200 "storable" => sub { Storable::nfreeze $_ }, 201 "storable-file" => sub { open my $fh, ">", \my $buf; Storable::nstore_fd $_, $fh; $buf }, 202 "bencode" => sub { require Convert::Bencode; Convert::Bencode::bencode ($_) }, 203 "clzf" => sub { require Compress::LZF; Compress::LZF::sfreeze_cr ($_) }, 204 "yaml" => sub { require YAML; YAML::Dump ($_) }, 205 "dumper" => sub { 206 require Data::Dumper; 207 #local $Data::Dumper::Purity = 1; # hopeless case 208 local $Data::Dumper::Terse = 1; 209 local $Data::Dumper::Indent = 1; 210 local $Data::Dumper::Useqq = 1; 211 local $Data::Dumper::Quotekeys = 0; 212 local $Data::Dumper::Sortkeys = 1; 213 Data::Dumper::Dumper($_) 214 }, 215 "dump" => sub { 216 require Data::Dump; 217 local $Data::Dump::TRY_BASE64 = 0; 218 Data::Dump::dump ($_) . "\n" 219 }, 220); 221 222$F{$opt_from} 223 or die "$opt_from: not a valid fromformat\n"; 224 225$T{$opt_to} 226 or die "$opt_from: not a valid toformat\n"; 227 228if ($opt_from ne "none") { 229 local $/; 230 binmode STDIN; # stupid perl sometimes thinks its funny 231 $_ = <STDIN>; 232} 233 234$_ = $F{$opt_from}->(); 235 236eval $opt_eval; 237die $@ if $@; 238 239$_ = $T{$opt_to}->(); 240 241binmode STDOUT; 242syswrite STDOUT, $_; 243 244 245 246