Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

JSON and Perl Objects - How to access data?

by harryhalpin (Initiate)
on Nov 18, 2007 at 22:15 UTC ( [id://651544]=perlquestion: print w/replies, xml ) Need Help??

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

I can convert my data from JSON to objects using the Perl JSON module (http://search.cpan.org/dist/JSON/), but I am having difficulty accessing the data in perl objects. The data appears to be in an array of hashes, but I cannot use any object accessor functions to get at the data. Here's a sample of the data:
{ "items" : [ { "name" : "Theodor Nelson", "id": "_333301" }, { "name": "Morton Heilig", "id": "_13204" } ] }
Here's a snippet of my code. Note $inventors_obj holds the data.
$inventors_obj = jsonToObj($inventors_json[0]); #I want to iterate through my list of inventors @inventors_array = $inventors_obj->{"items"};
But $inventors_obj->{"items} appears to be returning a single object, rather than an array. How can iterate through it, change things, and print it back to JSON?
#print name doesn't work, because the entire object is #stored at $inv +entors_array[0]. print $inventors_array[0]->{"name"} #So this doesn't work: print $inventors_array[1]->{"name"} #I am not sure if this is possible to even alter data #generically wit +h objects, even though I thought they were #really just arrays of hashes: $inventors_array[1]->{"name"} = "New Name"; #But I can do with an array of hashes... $inventors_array[1]{"name"} = "New Name";
However, if I convert the object to an array of hashes (how do I do this, "unblessing"?), can I get it back out in JSON? Is there a way I can manipulate it while keeping it as an object?

Replies are listed 'Best First'.
Re: JSON and Perl Objects - How to access data?
by jZed (Prior) on Nov 18, 2007 at 22:42 UTC
    The structure is a hashref that contains a single member with key "items" which consists of an arrayref that contains two hashrefs. So you have to dereference the arrayref to get its members something like this:
    for my $item( @{$inventors_object->{items}} ){ print $item->{name} . "\n"; };
    To change the data:
    $inventors_object->{items}->[0}->{name} = 'new name';
    To turn it back into a JSON string:
    my $new_json = objToJson( $inventors_object );
    update here is your mistake:
    @inventors_array = $inventors_obj->{"items"};
    You are trying to turn an arrayref into an array without dereferencing it. Instead you want:
    @inventors_array = @{ $inventors_obj->{"items"} };
      Man... thanks a lot.. i am trying to find useful info abt JSON and perl and this is pretty much the only one with some practical information. I still have not understood it completely but my sincere thanks. can u explain it to me wat exactly happens when u convert from json to perl obj. im lost in all the hashref and arrayref you are talking abt. Is it the object's structure that you are talking abt? if you could enumerate i would be grateful. thanks
      So how would you take the next step and represent this data in perl. For instance, if at the end of all this I want @name to hold 'Theodor Nelson','Morton Heilig' ,and @id to hold '_333301','_13204' how would I do that? I tried my @names = @{ $inventors_array[1]->{"name"}    }; but that gives me
      Can't use string ("Morton Heilig") as an ARRAY ref while "strict refs" + in use
      I'm not trying to define $names[Morton Heilig] = something, I'm trying to define $names[1]=Morton Heiling, or alternatively $names{_13204} = 'Morton Heilig'

        Good job searching to find this old thread! Your question is not related to JSON, but rather to perl data structures. See perlref.

        You should get in the habit of using Data::Dumper to examine your complex data structures. In this case, you still were unclear on how to access the nested data, but examining the structure is always the first step.

        (Note that jsonToObject in the OP is deprecated.)

        Here's an example that shows how to get your arrays. It's commented so you can see what's going on, and it deliberately uses more steps than optimal to be clear (if you really wanted to build separate arrays, you should probably use map).

        #!/usr/bin/perl use strict; use warnings; use feature qw/ say /; use Data::Dumper; use JSON; my $data = qq# { "items" : [ { "name" : "Theodor Nelson", "id": "_333301" }, { "name": "Morton Heilig", "id": "_13204" } ] } #; my $obj = from_json( $data ); my @names; my @ids; say Dumper $obj; # $obj is an anonymous hash with one key, 'items' my @items = @{ $obj->{'items'} }; # The value of the key 'items' is an anonymous array. # Here for simplicity we copy it into a new array. # We access it by deferencing it using @{ } foreach my $item ( @items ) { # Each element of the anonymous array is a hashref. # So $item is a hashref, not a scalar my $name = $item->{'name'}; my $id = $item->{'name'}; push @names, $name; push @ids, $id; } say 'Names: ' . join ', ', @names; say 'IDs: ' . join ', ', @ids; __END__
        A more idiomatic way to put the data into a hash keyed by ID as you suggested above:
        #!/usr/bin/perl use strict; use warnings; use feature qw/ say /; use Data::Dumper; use JSON; my $data = qq# { "items" : [ { "name" : "Theodor Nelson", "id": "_333301" }, { "name": "Morton Heilig", "id": "_13204" } ] } #; my $obj = from_json( $data ); my %names; $names{ $_->{'id'} } = $_->{'name'} for @{ $obj->{'items'} }; while ( my( $id, $name ) = each %names ) { say "$id: $name"; } __END__
        Output:
        $ perl 651544-2.pl _13204: Morton Heilig _333301: Theodor Nelson $
        And finally, how to access the names directly in the object:
        #!/usr/bin/perl use strict; use warnings; use feature qw/ say /; use Data::Dumper; use JSON; my $data = qq# { "items" : [ { "name" : "Theodor Nelson", "id": "_333301" }, { "name": "Morton Heilig", "id": "_13204" } ] } #; my $obj = from_json( $data ); say ${ $obj->{'items'}->[1] }{'name'}; # ^ ^ ^ ^ ^ ^ # | | | | | | # | is an arrayref | ----------- # | | | # | first element of which is a hash | # | | # the variable is value of the 'name' key __END__
        Hope this helps!

        The way forward always starts with a minimal test.
        Use map
        my @names = map { $_->{name} } @inventors_array ; my @id = map { $_->{id} } @inventors_array ; my %names = map { $_->{id}, $_->{name} } @inventors_array;
        poj
Re: JSON and Perl Objects - How to access data?
by stvn (Monsignor) on Nov 19, 2007 at 04:00 UTC

    You might want to give MooseX::Storage a look, it is a pretty thorough serialization framework and the JSON backend is pretty thorough (we use it extensively at $work).

    -stvn

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (6)
As of 2024-04-18 15:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found