In case it's useful to someone out there, I found that Rmap as used in pKai's sample code, didn't recurse as I wanted it to, for some Json strings anyway.

For instance, if you have a nested json object where some of the values in an object are the same (e.g. a list of keys with boolean values), decode_json uses JSON::true or JSON::false for the first instance it comes across, but then adds hash references to an existing true or false for all subsequent instances. This is presumably for performance? Whatever the reason, it caused me a bit of chin-scratching (not hard!).

Consider the following string of Json, (which might have been received as a post parameter, say):

{ "a": "x", "b": { "c":true, "d":false, "e":true, "f":false } }

If I tried this in pKai's code above, you don't get the required result - XML::Simple still complains:

$VAR1 = { 'a' => 'x', 'b' => { 'e' => bless( do{\(my $o = 1)}, 'JSON::XS::Boolean' + ), 'c' => $VAR1->{'b'}{'e'}, 'd' => bless( do{\(my $o = 0)}, 'JSON::XS::Boolean' + ), 'f' => $VAR1->{'b'}{'d'} } }; $VAR1 = { 'a' => 'x', 'b' => { 'e' => 'true', 'c' => bless( do{\(my $o = 1)}, 'JSON::XS::Boolean' + ), 'd' => 'false', 'f' => bless( do{\(my $o = 0)}, 'JSON::XS::Boolean' + ) } }; Can't encode a value of type: JSON::XS::Boolean at test2.pl line 13

The Rmap docs state that if there are multiple routes to the same node, only the first will be followed... so I'm pretty sure this is working as designed, but it's just not what I needed...

One way round it was just to repeat the same rmap_ref call against the object until there weren't any blessed objects left, but that seems dumb - it can't be very efficient? But it does work:

use strict; use warnings; use JSON; use XML::Simple; use Data::Rmap qw(rmap_ref); use Data::Dumper; my $text = '{"a":"x","b":{"c":true,"d":false,"e":true,"f":false}}'; my $result = decode_json($text); print Dumper($result); rmap_ref { $_ = "$_" if JSON::is_bool($_) } $result; print Dumper($result); rmap_ref { $_ = "$_" if JSON::is_bool($_) } $result; print Dumper($result); my $rec = XMLout( $result, RootName => 'root', SuppressEmpty => 1); print Dumper($rec);
$VAR1 = { 'a' => 'x', 'b' => { 'e' => bless( do{\(my $o = 1)}, 'JSON::XS::Boolean' + ), 'c' => $VAR1->{'b'}{'e'}, 'd' => bless( do{\(my $o = 0)}, 'JSON::XS::Boolean' + ), 'f' => $VAR1->{'b'}{'d'} } }; $VAR1 = { 'a' => 'x', 'b' => { 'e' => 'true', 'c' => bless( do{\(my $o = 1)}, 'JSON::XS::Boolean' + ), 'd' => 'false', 'f' => bless( do{\(my $o = 0)}, 'JSON::XS::Boolean' + ) } }; $VAR1 = { 'a' => 'x', 'b' => { 'e' => 'true', 'c' => 'true', 'd' => 'false', 'f' => 'false' } }; $VAR1 = '<root a="x"> <b c="true" d="false" e="true" f="false" /> </root> ';

In the end, I used something similar to ikegami's code above to make sure I walk a nested structure fully, but instead of using 1 or 0 to substitute the blessed JSON booleans, I used references, so that I could 'round trip' the resulting object using encode_json and get proper json booleans at the client (rather than the integers 1 or 0).

elsif (JSON::XS::is_bool($node)) { #$node += 0; # this results in 1 or 0 #$node = "$node"; # this results in "true" or "false" $node = ($node) ? \1 : \0; # this results in \1 or \0 (whic +h are mapped to Json true and false by encode_json...) }

There's probably a neat way to use Rmap to do the walking, but it was beyond my abilities I'm afraid. :(


In reply to Re^2: Converting boolean values in XMLout by Anonymous Monk
in thread Converting boolean values in XMLout by this_is_a_test

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.