0

I have a complex json data structure in perl like in the following example. I want to address an array element and store data.

Variable

$VAR1 = {
  'dummy' => 'foo',
  'profiles' => {
    'Tags' => [
                {
                  '###PLACEHOLDER###',
                }
              ],
}

I can for example add an element at "###PLACEHOLDER###" but want later in the perl script to add beneath that Placeholder additional information. Normally i would address these elements with $var->{profiles}->{Tags}->{PLACEHOLDER} but this is not working with an array.

I dont want to create everytime a foreach loop when i know the name exactly.

Any advice?

9
  • 1
    You can address the hash in the array (element 0) like this: $data{profiles}{Tags}[0]{"###PLACEHOLDER###"} = "data" Commented May 13, 2019 at 12:26
  • But this is an array and the values are not sorted so I cant be sure to get the correct one. Commented May 13, 2019 at 12:30
  • can you save the correct index (into the array) in a variable? Commented May 13, 2019 at 12:33
  • Yeah i think so, how can I do that? Commented May 13, 2019 at 12:34
  • 2
    I would advise you to create an object oriented class for such a complex nested data structure, then provide methods which allow you to add data in a manner that suits the semantics of your object. Commented May 13, 2019 at 12:35

2 Answers 2

1

[UPDATE: used dpathr instead of dpath for the references to structures]

[UPDATE: used dpath instead of dpathr for the references to elements]

Data::DPath can do what you require. Here's code which returns a reference to any structure (hash or array) which contains an element whose value is ###PLACEHOLDER###:

use strict;
use warnings;

use Data::Dumper;
use Data::DPath qw[ dpath dpathr ];

my $struct = {
    'dummy'    => 'foo',
    'profiles' => {
        'ARRAY' => [ '###PLACEHOLDER###' ],
        'HASH' => { key => '###PLACEHOLDER###' },
    },
};

my $path = dpath( '//[value eq "###PLACEHOLDER###"]/..' );

my @matches = $path->match( $struct );

print Dumper \@matches;

It results in:

$VAR1 = [
          [
            '###PLACEHOLDER###'
          ],
          {
            'key' => '###PLACEHOLDER###'
          }
        ];

If you want direct access to the element, change the path to

my $path = dpathr( '//*[value eq "###PLACEHOLDER###"]' );

with the result:

$VAR1 = [
          \'###PLACEHOLDER###',
          \'###PLACEHOLDER###'
        ];
Sign up to request clarification or add additional context in comments.

2 Comments

It does on my machine. What does it do on your machine?
Right. Good catch. Nested references to the structures. I'll fix that. If the OP wants to directly change the ###PLACEHOLDER### string they'll still need a reference to the value. [Now I see what I did. I switched dpathr with dpath for the two cases when I was creating the post. Ooops]
1

It's not clear to me what you what "adding an element at ###PLACEHOLDER###" means. Elements can be added to arrays and hashes, and it's not clear to which array or hash you are referring.


To append an element to the array referenced by $var->{profiles}{Tags}, use

push @{ $var->{profiles}{Tags} }, $val;

This results in

$VAR1 = {
  'dummy' => 'foo',
  'profiles' => {
    'Tags' => [
                {
                  '###PLACEHOLDER###' => undef,
                },
                $val
              ],
}

To add an element to the hash referenced by the last element of the array referenced by $var->{profiles}{Tags}, use

$var->{profiles}{Tags}[-1]{$key} = $val;

This results in

$VAR1 = {
  'dummy' => 'foo',
  'profiles' => {
    'Tags' => [
                {
                  '###PLACEHOLDER###' => undef,
                  $key => $val,
                },
              ],
}

Of course, if $key is ###PLACEHOLDER###, this results in

$VAR1 = {
  'dummy' => 'foo',
  'profiles' => {
    'Tags' => [
                {
                  '###PLACEHOLDER###' => $val,
                },
              ],
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.