Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Perl structure to Javacript-ready JSON

by Jeppe (Monk)
on Nov 25, 2014 at 13:21 UTC ( [id://1108347]=perlquestion: print w/replies, xml ) Need Help??

Jeppe has asked for the wisdom of the Perl Monks concerning the following question:

Esteemed monks, I'm essentially trying to escape the contents of a JSON structure.
my $hashref = { abc => "abc'abc" };
This should become
{"abc":"abc\'abc"}
, and it must work for blessed references as well. I'm currently using the JSON module, but I'm not married to it. Ideally, this would have been resolved by a hook in the JSON module - but that does not seem to be available. What other options do I have?

Replies are listed 'Best First'.
Re: Perl structure to Javacript-ready JSON
by ikegami (Patriarch) on Nov 25, 2014 at 16:31 UTC

    The following isn't JSON:

    {"abc":"abc\'abc"}

    What are you trying to do? You might be trying to generate a JavaScript string literal from JSON, but then you'd want something like the following.

    '{"abc":"abc\'abc"}'

    If that's what you want, you can use the following:

    { my %translations = ( "\r" => "\\r", "\n" => "\\n", "'" => "\\'", "\\" => "\\\\", ); my $meta_chars_class = join '', map quotemeta, keys %translations; my $meta_chars_re = qr/([$meta_chars_class])/; sub text_to_jslit { my $text = shift; $text =~ s/$meta_chars_re/$translations{$1}/g; return "'$text'"; } }

    As a Template-Toolkit plugin:

    package Template::Plugin::JavaScriptLiteral; use strict; use warnings; use Template::Plugin::Filter qw( ); our @ISA = 'Template::Plugin::Filter'; my %translations = ( "\r" => "\\r", "\n" => "\\n", "'" => "\\'", "\\" => "\\\\", ); my $meta_chars_class = join '', map quotemeta, keys %translations; my $meta_chars_re = qr/([$meta_chars_class])/; sub init { my $self = shift; $self->install_filter('jslit'); return $self; } sub filter { my ($self, $text) = @_; $text =~ s/$meta_chars_re/$translations{$1}/g; return "'$text'"; } 1;

    For example,

    // PARAMS: { data => { abc => "abc'abc" } } [% USE JSON %] [% USE JavaScriptLiteral %] var json = [% data | json | jslit %]; alert(json); // {"abc":"abc'abc"}

    However, one usually wants to assign the JSON to a JS var, not a string representation of it.

    // PARAMS: { data => { abc => "abc'abc" } } [% USE JSON %] var data = [% data | json %]; alert(data.abc); // abc'abc
      Thanks! I guess my statement was a bit wooly. I'm really trying to do create a javascript literal that I can include like this:
      var data = JSON.parse('{"abc":"abc\'abc"}');
      .. and must therefore escape the string. I've written code that's essentially like in proposal one. Thanks!
        If you know the JSON is valid, var data = {"abc":"abc'abc"}; is equivalent.
Re: Perl structure to Javacript-ready JSON
by hippo (Bishop) on Nov 25, 2014 at 15:48 UTC

    I have not used it myself (no need) but from the documentation, it sounds as though JavaScript::Value::Escape may be what you are looking for. If not, please say why not because it sounds like escaping literals for embedding into Javascript is its raison d'être.

Re: Perl structure to Javacript-ready JSON
by MidLifeXis (Monsignor) on Nov 25, 2014 at 16:07 UTC

    Not sure why you would think that a JSON module should provide a hook for providing data that is not, well, just a different form of valid JSON.

    Update: note really invalid, just not the simplest form.

    --MidLifeXis

      > ... for providing data that is not, well, JSON.

      Shouldn't "\'" and "'" be synonymous in the end?

      Quoting of non-meta characters does no harm, at least in Perl.

      So I don't understand why it's not JSON, it might be redundant but it's still valid.

      Cheers Rolf

      (addicted to the Perl Programming Language and ☆☆☆☆ :)

        Point taken, tested, and my response updated.

        It still seems, imo, that this is something outside of the scope of what the JSON module should be providing. I suppose, if one really wanted to, one could just escape every non-escaped character and be done with it.

        --MidLifeXis

Re: Perl structure to Javacript-ready JSON
by LanX (Saint) on Nov 25, 2014 at 15:24 UTC

      Well, Jeppe already knew about JSON since he's using it already. And there are other modules that do the same thing (JSON::DWIM will work the same on blessed or not blessed objects for exemple). But as far as I understand the issue here is to escape some chars (the single quote at least apparently) in strings. And unlike Data::Dump, JSON doesn't seem to provide a call back to allow custom output for any data type (objects can have a method to convert themselves to JSON, but here the strings are not blessed).

      Jeppe, wouldn't s/'/\\'/g; on the output JSON be enough?

        OK, right, sorry.

        My fault was that I read it as JSON has a bug in escaping quotes!

        ( JS - contrary to Perl - doesn't give single and double quotes different meanings, but that doesn't mean they need to be escaped, so no bug! )

        so whats happening here is that Jeppe wants the data altered, and IMHO this should already be done on Perl's side before escaping.

        Your suggestion of a general s/'/\\'/g would only work if the JSON output doesn't use single quotes as delimiter.¹

        Cheers Rolf

        (addicted to the Perl Programming Language and ☆☆☆☆ :)

        update

        ¹) ah sorry, I didn't know that single quotations are invalid in JSON

        from JSON::PP

        allow_singlequote $json = $json->allow_singlequote([$enable]) If $enable is true (or missing), then "decode" will accept JSON + strings quoted by single quotations that are invalid JSON format.
Re: Perl structure to Javacript-ready JSON
by perlancar (Hermit) on Nov 29, 2014 at 11:25 UTC
    You might also want to take a look at Data::Clean::JSON which will sanitize things like circular references, regexps, and other "dangerous" stuffs so that the final result is safe to just feed to JSON::encode_json().

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1108347]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2024-03-29 15:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found