Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't select specific array item (question) #26

Closed
davewood opened this issue Jan 11, 2023 · 13 comments
Closed

Can't select specific array item (question) #26

davewood opened this issue Jan 11, 2023 · 13 comments

Comments

@davewood
Copy link
Contributor

davewood commented Jan 11, 2023

#!/usr/bin/env perl
use 5.032;
use warnings;
use Data::DPath::Path;

my $query_path = '/*/*[2]/.[value eq "street"]/../*[3]/.[0]';
my $input_pl = [
  [ 1, "SUCCESS", 1000, "" ],
  [ 2, "ATTR", "street", "street1" ],
  [ 3, "ATTR", "street", "street2" ]
];

my $dpath  = Data::DPath::Path->new( path => $query_path );
my @result = $dpath->match($input_pl);

use Data::Dumper;
say Dumper(\@result);

this prints

$VAR1 = [
          'street1',
          'street2'
        ];

What path selects only one specific array item? For example, only street2.

@renormalist
Copy link
Owner

Not sure yet if I correctly understand what the criteria for 'street2' is. You already selected the [3] element, in which street2 appears. You could specify that criteria further like

my $query_path = '/*/*[2]/.[value eq "street"]/../*[3]/.[value eq "street2"]';

But that's probably not helpful when you already know it in advance, so not sure...

@davewood
Copy link
Contributor Author

davewood commented Jan 16, 2023

I want to select the 2nd array item, via index.

my $query_path = '/*/*[2]/.[value eq "street"]/../*[3]/.[idx == 1]';

but this returns

$VAR1 = [];

while
my $query_path = '/*/*[2]/.[value eq "street"]/../*[3]/.[idx == 0]';
returns

$VAR1 = [
          'street1',
          'street2'
        ];

How do I access the array refs first or second item so that I get this result?

$VAR1 = [
          'street2'
        ];

@renormalist
Copy link
Owner

Hm, that array containing [street1, street2] is the result of the dpath query, containing everything it found with the dpath somewhere in the data structure. So it's technically not in the data structure and therefore not addressable with the dpath.

So you would query with a dpath like you quite did already:

my $query_path = '/*/*[2]/.[value eq "street"]/../*[3]';

and on the result choose the $result[1].

@davewood
Copy link
Contributor Author

I cant use perl code to work with the dpath result, the query needs to return

$VAR1 = [
          'street2'
        ];

is there no query that does that?

@renormalist
Copy link
Owner

Not on the result set.

In dpath logic you need to express it from the point of view of the actual data structure.

So you could early on in the path filter out the wrong indexes, like with *[idx > 1]:

my $query_path = '/*[idx > 1]/*[value eq "street"]/../*[3]';

But still it all comes down to your knowledge about the result in advance.

@davewood
Copy link
Contributor Author

your solution doesnt work for our use case.

I need to select all nodes from $input_pl that have "street" as the third item. And after that I want to select the 4th item by index.

so

1st step should yield

  [ 2, "ATTR", "street", "street1" ],
  [ 3, "ATTR", "street", "street2" ]

what if the source data would look like this `["item1","item2"]

is there no query that returns either "item1" or "item2" using an index?

ps: I appreciate your help.

@renormalist
Copy link
Owner

I'm quite sure I understand your problem. However, whether that item you want to access is the n-th item depends on the data structure in which you search. You are looking at the result where that "street2" could result from anywhere in the data structure. That gives us 3 options:

  1. Either you know that in your your data structure it's the 4th item, then you can encode it into the dpath, like my last proposal.

  2. Or, you don't know your data structure and so you can't know whether it's the 4th item.

  3. If you don't know the data structure, but know the result, like in your question, then you have to work on that result data. Which is outside the scope of what the dpath iterates.

I can see that you might have a restricted environment where you can only change the dpath but nothing else.

But as you would have to change the dpath's index anyway to reach the 4th result, respectively any other index every time the input data structure changes, then why not do that at the beginning of the dpath as I suggested?

Alternatively, maybe in your environment you can daisy-chain dpath operations and feed the result into the next with /*[3]?

@renormalist
Copy link
Owner

Actually, you already solved that "4th item problem" with your *[3] part. I'm talking about the "second result item" problem. It's a bit confusing...

@davewood
Copy link
Contributor Author

I will try with another example, because I am having a hard time putting my question into understandable words. :)

my $input = [
  [ "foo_1", "bar_1" ],
  [ "foo_2", "bar_2" ],
  ...
  [ "foo_n", "bar_n" ],
  [ "address", "street1" ],
  [ "address", "street2" ],
];
  • I dont know how many items are in the array before the "address" items come.
  • select items where [0] equals "address"

/*/*[0]/.[value eq "address"]/..

$VAR1 = [
          [
            'address',
            'street1'
          ],
          [
            'address',
            'street2'
          ]
        ];

now select the 2nd item, I cant figure out how to do that, and I feel like I am running in a circle. :p

ps: I suppose this is not a DPath issue but rather my mind not grasping how to use it. my apologies. I dont understand why I can filter out the nodes I want but after that I cant select a specific one by index.

@renormalist
Copy link
Owner

I absolutely understand your problem and I feel sorry to not have better answers.

The answer to your last question is: dpath works on the nodes - not on its own result after that. But that is exactly what you want. You want a match on the result of a match so far. That's different data set than the actual input data structure.

So maybe you can extend the application to accept two (or more) dpaths to allow a "chain" of dpath matching.

The first does what you already do now.
The second dpath works on the result of the previous step, in your case with /*[1] to select street_2.
And possibly more, each referring to the result of the previous step.

We could invent a syntax for DPath "chains", like /this/is/path1 :: /and/this/is/path2 but that's a tricky parsing problem and outside my currently available time budget.

@renormalist
Copy link
Owner

One yould invent a "container syntax for dpath chains" which is easier to parse with the currently used balanced expression parser and even recognizable, like this:

{/this/is/path1}{/and/this/is/path2}{/and/even/a/path3}

but still: it doesn't exist yet and I'm really low on time and energy.

@davewood
Copy link
Contributor Author

I think I understood the modules constraints now and found a solution for my problem. namely, chaining two path executions as you advised.

thank you for your effort to help me!

@renormalist
Copy link
Owner

Nice. Thanks for your patience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants