.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
. ds C`
. ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\"
.\" If the F register is >0, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.nr rF 0
.if \n(.g .if rF .nr rF 1
.if (\n(rF:(\n(.g==0)) \{\
. if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. if !\nF==2 \{\
. nr % 0
. nr F 2
. \}
. \}
.\}
.rr rF
.\" ========================================================================
.\"
.IX Title "Data::DPath 3pm"
.TH Data::DPath 3pm "2022-11-29" "perl v5.36.0" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
Data::DPath \- DPath is not XPath!
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
.Vb 7
\& use Data::DPath \*(Aqdpath\*(Aq;
\& my $data = {
\& AAA => { BBB => { CCC => [ qw/ XXX YYY ZZZ / ] },
\& RRR => { CCC => [ qw/ RR1 RR2 RR3 / ] },
\& DDD => { EEE => [ qw/ uuu vvv www / ] },
\& },
\& };
\&
\& # Perl 5.8 style
\& my @resultlist = dpath(\*(Aq/AAA/*/CCC\*(Aq)\->match($data); # ( [\*(AqXXX\*(Aq, \*(AqYYY\*(Aq, \*(AqZZZ\*(Aq], [ \*(AqRR1\*(Aq, \*(AqRR2\*(Aq, \*(AqRR3\*(Aq ] )
\&
\& # Perl 5.10 style using overloaded smartmatch operator
\& my $resultlist = $data ~~ dpath \*(Aq/AAA/*/CCC\*(Aq; # [ [\*(AqXXX\*(Aq, \*(AqYYY\*(Aq, \*(AqZZZ\*(Aq], [ \*(AqRR1\*(Aq, \*(AqRR2\*(Aq, \*(AqRR3\*(Aq ] ]
.Ve
.PP
Note that the \f(CW\*(C`match()\*(C'\fR function returns an array but the overloaded
\&\f(CW\*(C`~~\*(C'\fR operator returns an array reference (that's a limitation of
overloading).
.PP
Various other example paths from \f(CW\*(C`t/data_dpath.t\*(C'\fR (not neccessarily
fitting to above data structure):
.PP
.Vb 12
\& $data ~~ dpath \*(Aq/AAA/*/CCC\*(Aq
\& $data ~~ dpath \*(Aq/AAA/BBB/CCC/../..\*(Aq # parents (..)
\& $data ~~ dpath \*(Aq//AAA\*(Aq # anywhere (//)
\& $data ~~ dpath \*(Aq//AAA/*\*(Aq # anywhere + anystep
\& $data ~~ dpath \*(Aq//AAA/*[size == 3]\*(Aq # filter by arrays/hash size
\& $data ~~ dpath \*(Aq//AAA/*[size != 3]\*(Aq # filter by arrays/hash size
\& $data ~~ dpath \*(Aq/"EE/E"/CCC\*(Aq # quote strange keys
\& $data ~~ dpath \*(Aq/AAA/BBB/CCC/*[1]\*(Aq # filter by array index
\& $data ~~ dpath \*(Aq/AAA/BBB/CCC/*[ idx == 1 ]\*(Aq # same, filter by array index
\& $data ~~ dpath \*(Aq//AAA/BBB/*[key eq "CCC"]\*(Aq # filter by exact keys
\& $data ~~ dpath \*(Aq//AAA/*[ key =~ /CC/ ]\*(Aq # filter by regex matching keys
\& $data ~~ dpath \*(Aq//CCC/*[ value eq "RR2" ]\*(Aq # filter by values of hashes
.Ve
.PP
See full details in \f(CW\*(C`t/data_dpath.t\*(C'\fR.
.PP
You can get references into the \f(CW$data\fR data structure by using \f(CW\*(C`dpathr\*(C'\fR:
.PP
.Vb 2
\& $data ~~ dpathr \*(Aq//AAA/BBB/*\*(Aq
\& # etc.
.Ve
.PP
You can request iterators to do incremental searches using \f(CW\*(C`dpathi\*(C'\fR:
.PP
.Vb 11
\& my $benchmarks_iter = dpathi($data)\->isearch("//Benchmark");
\& while ($benchmarks_iter\->isnt_exhausted)
\& {
\& my $benchmark = $benchmarks_iter\->value;
\& my $ancestors_iter = $benchmark\->isearch ("/::ancestor");
\& while ($ancestors_iter\->isnt_exhausted)
\& {
\& my $ancestor = $ancestors_iter\->value;
\& print Dumper( $ancestor\->deref );
\& }
\& }
.Ve
.PP
This finds all elements anywhere behind a key \*(L"Benchmark\*(R" and for each
one found print all its ancestors, respectively. See also chapter
Iterator style.
.SH "ABOUT"
.IX Header "ABOUT"
With this module you can address points in a datastructure by
describing a \*(L"path\*(R" to it using hash keys, array indexes or some
wildcard-like steps. It is inspired by XPath but differs from it.
.SS "Why not XPath?"
.IX Subsection "Why not XPath?"
XPath is for \s-1XML.\s0 DPath is for data structures, with a stronger Perl
focus.
.PP
Although \s-1XML\s0 documents are data structures, they are special.
.PP
Elements in \s-1XML\s0 always have an order which is in contrast to hash keys
in Perl.
.PP
\&\s-1XML\s0 elements names on same level can be repeated, not so in hashes.
.PP
\&\s-1XML\s0 element names are more limited than arbitrary strange hash keys.
.PP
\&\s-1XML\s0 elements can have attributes and those can be addressed by XPath;
Perl data structures do not need this. On the other side, data
structures in Perl can contain blessed elements, DPath can address
this.
.PP
\&\s-1XML\s0 has namespaces, data structures have not.
.PP
Arrays starting with index 1 as in XPath would be confusing to read
for data structures.
.PP
DPath allows filter expressions that are in fact just Perl expressions
not an own sub language as in XPath.
.SS "Comparison with Data::Path"
.IX Subsection "Comparison with Data::Path"
There is a similar approach on \s-1CPAN,\s0 Data::Path. Here is
a comparison matrix between Data::Path and
Data::DPath.
.PP
(Warning: \fBalpha\fR grade comparison ahead, not yet fully verified,
only evaluated by reading the source. Speed comparison not really
benchmarked.)
.PP
.Vb 3
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\& Criteria Data::Path Data::DPath
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& real XPath syntax no no
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& allow strange, YES YES
\& non\-xml but
\& perl\-like although
\& hash keys limited,
\& see next
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& allows special no YES
\& chars of own
\& path syntax in you can quote everything
\& hash keys
\& ("/[]|*.")
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& call subs in YES no
\& data structure,
\& like:
\& /method()
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& callbacks on YES no
\& not found keys
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& element "//" no YES
\& for "ANYWHERE"
\& (//foo/bar)
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& element "." no YES
\& for "NOSTEP" or
\& "actual position"
\& (/.[filter expr])
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& element ".." no YES
\& for "PARENT"
\& (//foo/..)
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& element "::ancestor" no YES
\& for "ANCESTOR"
\& (//foo/::ancestor)
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& element no YES
\& "::ancestor\-or\-self"
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& element "*" no YES
\& for "ANYSTEP" or
\& "all subelements"
\& (/foo/*)
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& array access YES YES
\& like /foo[4]
\& although including negative indexes
\& limited and whitespace awareness
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& complex no YES
\& filter expressions
\& like full Perl expressions
\& /foo[size == 3] or plus sugar functions
\& /.[isa("Foo::Bar")]
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& works with YES YES
\& blessed subelements
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& arrays start YES YES
\& with index 0
\& (in contrast
\& to 1 as in XPath)
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& array semantics /foo[2] /foo/*[2]
\& is a bit different
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& handling of croak RETURN EMPTY
\& not matching
\& paths but can be
\& overwritten
\& as callback
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& usage sugar none overloaded \*(Aq~~\*(Aq operator
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& Speed FAST quite fast
\&
\& \- raw Perl \- probably comparable
\& \- considered fast speed with expressions
\& that Data::Path handles
\& \- slower on fuzzy paths,
\& eg. with many "//" in it
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& Perl Versions 5.6+ 5.8+
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
\&
\& Install chance 100% 90%
\& (http://deps
\& .cpantesters
\& .org)
\&
\& \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
.Ve
.PP
\fISummary\fR
.IX Subsection "Summary"
.PP
Generally Data::Path is for simpler use cases but does
not suffer from surrounding meta problems: it has no dependencies, is
fast and works on practically every Perl version.
.PP
Whereas Data::DPath provides more XPath-alike features,
but isn't quite as fast and has more dependencies.
.SH "Security warning"
.IX Header "Security warning"
\&\fBWatch out!\fR This module \f(CW\*(C`eval\*(C'\fRs parts of provided dpaths (in
particular: the filter expressions). Don't use it if you don't trust
your paths.
.PP
Since v0.41 the filter expressions are secured using Safe.pm
to only allow basic Perl core ops. This provides more safety but is
also significantly slower. To unrestrict this to pre\-v0.41 raw \f(CW\*(C`eval\*(C'\fR
behaviour you can set \f(CW$Data::DPath::USE_SAFE\fR to False:
.PP
.Vb 2
\& local $Data::DPath::USE_SAFE;
\& # dpath \*(Aq//CCC//*[ unsecure_perl_expression ]\*(Aq
.Ve
.PP
Read Safe.pm to understand how secure this is.
.SH "FUNCTIONS"
.IX Header "FUNCTIONS"
.ie n .SS "dpath( $path_str )"
.el .SS "dpath( \f(CW$path_str\fP )"
.IX Subsection "dpath( $path_str )"
Meant as the front end function for everyday use of Data::DPath. It
takes a path string and returns a \f(CW\*(C`Data::DPath::Path\*(C'\fR object on which
the match method can be called with data structures and the operator
\&\f(CW\*(C`~~\*(C'\fR is overloaded.
.PP
The function is prototyped to take exactly one argument so that you
can omit the parens in many cases.
.PP
See \s-1SYNOPSIS.\s0
.ie n .SS "dpathr( $path_str )"
.el .SS "dpathr( \f(CW$path_str\fP )"
.IX Subsection "dpathr( $path_str )"
Same as \f(CW\*(C`dpath\*(C'\fR but toggles that results are references to the
matched points in the data structure.
.ie n .SS "dpathi( $data )"
.el .SS "dpathi( \f(CW$data\fP )"
.IX Subsection "dpathi( $data )"
This is a different, iterator style, approach.
.PP
You provide the data structure on which to work and get back a current
context containing the root element (as if you had searched for the
path \f(CW\*(C`/\*(C'\fR), and now you can do incremental searches using \f(CW\*(C`isearch\*(C'\fR.
.PP
See chapter Iterator style below for details.
.SH "API METHODS"
.IX Header "API METHODS"
.ie n .SS "match( $data, $path )"
.el .SS "match( \f(CW$data\fP, \f(CW$path\fP )"
.IX Subsection "match( $data, $path )"
Returns an array of all values in \f(CW$data\fR that match the \f(CW$path\fR.
.ie n .SS "matchr( $data, $path )"
.el .SS "matchr( \f(CW$data\fP, \f(CW$path\fP )"
.IX Subsection "matchr( $data, $path )"
Returns an array ref of all values in \f(CW$data\fR that match the \f(CW$path\fR.
.SH "OPERATOR"
.IX Header "OPERATOR"
.SS "~~"
.IX Subsection "~~"
Does a \f(CW\*(C`match\*(C'\fR of a dpath against a data structure.
.PP
Due to the \fBmatching\fR nature of DPath the operator \f(CW\*(C`~~\*(C'\fR should make
your code more readable.
.SH "THE DPATH LANGUAGE"
.IX Header "THE DPATH LANGUAGE"
.SS "Synopsis"
.IX Subsection "Synopsis"
.Vb 10
\& /AAA/BBB/CCC
\& /AAA/*/CCC
\& //CCC/*
\& //CCC/*[2]
\& //CCC/*[size == 3]
\& //CCC/*[size != 3]
\& /"EE/E"/CCC
\& /AAA/BBB/CCC/*[1]
\& /AAA/BBB/CCC/*[ idx == 1 ]
\& //AAA/BBB/*[key eq "CCC"]
\& //AAA/*[ key =~ /CC/ ]
\& //CCC/*[value eq "RR2"]
\& //.[ size == 4 ]
\& /.[ isa("Funky::Stuff") ]/.[ size == 5 ]/.[ reftype eq "ARRAY" ]
.Ve
.SS "Modeled on XPath"
.IX Subsection "Modeled on XPath"
The basic idea is that of XPath: define a way through a datastructure
and allow some funky ways to describe fuzzy ways. The syntax is
roughly looking like XPath but in fact have not much more in common.
.PP
\fISome wording\fR
.IX Subsection "Some wording"
.PP
I call the whole path a, well, \fBpath\fR.
.PP
It consists of single (\fBpath\fR) \fBsteps\fR that are divided by the path
separator \f(CW\*(C`/\*(C'\fR.
.PP
Each step can have a \fBfilter\fR appended in brackets \f(CW\*(C`[]\*(C'\fR that narrows
down the matching set of results.
.PP
Additional functions provided inside the filters are called, well,
\&\fBfilter functions\fR.
.PP
Each step has a set of \fBpoint\fRs relative to the set of points before
this step, all starting at the root of the data structure.
.SS "Special elements"
.IX Subsection "Special elements"
.ie n .IP """//""" 4
.el .IP "\f(CW//\fR" 4
.IX Item "//"
Anchors to any hash or array inside the data structure below the
currently found points (or the root).
.Sp
Typically used at the start of a path to anchor the path anywhere
instead of only the root node:
.Sp
.Vb 1
\& //FOO/BAR
.Ve
.Sp
but can also happen inside paths to skip middle parts:
.Sp
.Vb 1
\& /AAA/BBB//FARAWAY
.Ve
.Sp
This allows any way between \f(CW\*(C`BBB\*(C'\fR and \f(CW\*(C`FARAWAY\*(C'\fR.
.ie n .IP """*""" 4
.el .IP "\f(CW*\fR" 4
.IX Item "*"
Matches one step of any value relative to the current points (or the
root). This step might be any hash key or all values of an array in
the step before.
.ie n .IP """..""" 4
.el .IP "\f(CW..\fR" 4
.IX Item ".."
Matches the parent element relative to the current points.
.ie n .IP """::ancestor""" 4
.el .IP "\f(CW::ancestor\fR" 4
.IX Item "::ancestor"
Matches all ancestors (parent, grandparent, etc.) of the current node.
.ie n .IP """::ancestor\-or\-self""" 4
.el .IP "\f(CW::ancestor\-or\-self\fR" 4
.IX Item "::ancestor-or-self"
Matches all ancestors (parent, grandparent, etc.) of the current node
and the current node itself.
.ie n .IP """.""" 4
.el .IP "\f(CW.\fR" 4
.IX Item "."
A \*(L"no step\*(R". This keeps passively at the current points, but allows
incrementally attaching filters to points or to otherwise hard to
reach steps, like the top root element \f(CW\*(C`/\*(C'\fR. So you can do:
.Sp
.Vb 1
\& /.[ FILTER ]
.Ve
.Sp
or chain filters:
.Sp
.Vb 1
\& /AAA/BBB/.[ filter1 ]/.[ filter2 ]/.[ filter3 ]
.Ve
.Sp
This way you do not need to stuff many filters together into one huge
killer expression and can more easily maintain them.
.Sp
See Filters for more details on filters.
.IP "If you need those special elements to be not special but as key names, just quote them:" 4
.IX Item "If you need those special elements to be not special but as key names, just quote them:"
.Vb 9
\& /"*"/
\& /"*"[ filter ]/
\& /"::ancestor"/
\& /".."/
\& /".."[ filter ]/
\& /"."/
\& /"."[ filter ]/
\& /"//"/
\& /"//"[ filter ]/
.Ve
.ie n .SS "Difference between ""/step[filter]"" vs. ""/step/.[filter]"" vs. ""/step/*[filter]"""
.el .SS "Difference between \f(CW/step[filter]\fP vs. \f(CW/step/.[filter]\fP vs. \f(CW/step/*[filter]\fP"
.IX Subsection "Difference between /step[filter] vs. /step/.[filter] vs. /step/*[filter]"
The filter applies to the matched points of the step to which it is
applied, therefore \f(CW\*(C`/part[filter]\*(C'\fR is the normal form, but see below
how this affects array access.
.PP
The \*(L"no step\*(R" \*(L"/.\*(R" stays on the current step, therefore
\&\f(CW\*(C`/part/.[filter]\*(C'\fR should be the same as \f(CW\*(C`/part[filter]\*(C'\fR.
.PP
Lastly, \f(CW\*(C`/part/*[filter]\*(C'\fR means: take all the sub elements (\*(L"*\*(R")
\&\fBbelow\fR \*(L"step\*(R" and apply the filter to those. The most common use is
to take \*(L"all\*(R" elements of an array and chose one element via index:
\&\f(CW\*(C`/step/*[4]/\*(C'\fR. This takes the fifth element of the array inside
\&\*(L"step\*(R". This is explained in even more depth in the next section.
.ie n .SS "Difference between ""/affe[2]"" vs. ""/affe/*[2]"""
.el .SS "Difference between \f(CW/affe[2]\fP vs. \f(CW/affe/*[2]\fP"
.IX Subsection "Difference between /affe[2] vs. /affe/*[2]"
\&\fBRead carefully.\fR This is different from what you probably expect
when you know XPath.
.PP
In \fBXPath\fR \*(L"/affe[2]\*(R" would address an item of all elements named
\&\*(L"affe\*(R" on this step. This is because in XPath elements with the same
name can be repeated, like this:
.PP
.Vb 5
\&
\& Pavian
\& Gorilla
\& Schimpanse
\&
.Ve
.PP
and \*(L"//affe[2]\*(R" would get \*(L"Schimpanse\*(R" (we ignore the fact that in
XPath array indexes start with 1, not 0 as in DPath, so we would
actually get \*(L"Gorilla\*(R"; anyway, both are funky fellows).
.PP
So what does \*(L"/affe[2]\*(R" return in DPath? Nothing! It makes no sense,
because \*(L"affe\*(R" is interpreted as a hash key and hash keys can not
repeat in Perl data structures.
.PP
So what you often want in DPath is to look at the elements \fBbelow\fR
\&\*(L"affe\*(R" and takes the third of them, e.g. in such a structure:
.PP
.Vb 6
\& { affe => [
\& \*(AqPavian\*(Aq,
\& \*(AqGorilla\*(Aq,
\& \*(AqSchimpanse\*(Aq
\& ]
\& }
.Ve
.PP
the path \*(L"/affe/*[2]\*(R" would return \*(L"Schimpanse\*(R".
.SS "Filters"
.IX Subsection "Filters"
Filters are conditions in brackets. They apply to all elements that
are directly found by the path part to which the filter is appended.
.PP
Internally the filter condition is part of a \f(CW\*(C`grep\*(C'\fR construct
(exception: single integers, they choose array elements). See below.
.PP
Examples:
.ie n .IP """/FOO/*[2]/""" 4
.el .IP "\f(CW/FOO/*[2]/\fR" 4
.IX Item "/FOO/*[2]/"
A single integer as filter means choose an element from an array. So
the \f(CW\*(C`*\*(C'\fR finds all subelements that follow current step \f(CW\*(C`FOO\*(C'\fR and the
\&\f(CW\*(C`[2]\*(C'\fR reduces them to only the third element (index starts at 0).
.ie n .IP """/FOO/*[ idx == 2 ]/""" 4
.el .IP "\f(CW/FOO/*[ idx == 2 ]/\fR" 4
.IX Item "/FOO/*[ idx == 2 ]/"
The \f(CW\*(C`*\*(C'\fR is a step that matches all elements after \f(CW\*(C`FOO\*(C'\fR, but with
the filter only those elements are chosen that are of index 2. This is
actually the same as just \f(CW\*(C`/FOO/*[2]\*(C'\fR.
.ie n .IP """/FOO/*[key eq ""CCC""]""" 4
.el .IP "\f(CW/FOO/*[key eq ``CCC'']\fR" 4
.IX Item "/FOO/*[key eq ""CCC""]"
In all elements after \f(CW\*(C`FOO\*(C'\fR it matches only those elements whose key
is \*(L"\s-1CCC\*(R".\s0
.ie n .IP """/FOO/*[key =~ /CCC/ ]""" 4
.el .IP "\f(CW/FOO/*[key =~ /CCC/ ]\fR" 4
.IX Item "/FOO/*[key =~ /CCC/ ]"
In all elements after step \f(CW\*(C`FOO\*(C'\fR it matches only those elements whose
key matches the regex \f(CW\*(C`/CCC/\*(C'\fR. It is actually just Perl code inside
the filter which works in a grep{}\-like context.
.ie n .IP """//FOO/*[value eq ""RR2""]""" 4
.el .IP "\f(CW//FOO/*[value eq ``RR2'']\fR" 4
.IX Item "//FOO/*[value eq ""RR2""]"
Find elements below \f(CW\*(C`FOO\*(C'\fR that have the value \f(CW\*(C`RR2\*(C'\fR.
.Sp
Combine this with the parent step \f(CW\*(C`..\*(C'\fR:
.ie n .IP """//FOO/*[value eq ""RR2""]/..""" 4
.el .IP "\f(CW//FOO/*[value eq ``RR2'']/..\fR" 4
.IX Item "//FOO/*[value eq ""RR2""]/.."
Find such an element below \f(CW\*(C`FOO\*(C'\fR where an element with value \f(CW\*(C`RR2\*(C'\fR
is contained.
.ie n .IP """//FOO[size >= 3]""" 4
.el .IP "\f(CW//FOO[size >= 3]\fR" 4
.IX Item "//FOO[size >= 3]"
Find \f(CW\*(C`FOO\*(C'\fR elements that are arrays or hashes of size 3 or bigger.
.SS "Filter functions"
.IX Subsection "Filter functions"
The filter condition is internally part of a \f(CW\*(C`grep\*(C'\fR over the current
subset of values. So you can write any condition like in a grep and
also use the variable \f(CW$_\fR.
.PP
Additional filter functions are available that are usually written to
use \f(CW$_\fR by default. See Data::DPath::Filters
for complete list of available filter functions.
.PP
Here are some of them:
.IP "idx" 4
.IX Item "idx"
Returns the current index inside array elements.
.Sp
Please note that the current matching elements might not be in a
defined order if resulting from anything else than arrays.
.IP "size" 4
.IX Item "size"
Returns the size of the current element. If it is an arrayref it
returns number of elements, if it's a hashref it returns number of
keys, if it's a scalar it returns 1, everything else returns \-1.
.IP "key" 4
.IX Item "key"
Returns the key of the current element if it is a hashref. Else it
returns undef.
.IP "value" 4
.IX Item "value"
Returns the value of the current element. If it is a hashref, return
the value. If a scalar, return the scalar. Else return undef.
.SS "Special characters"
.IX Subsection "Special characters"
There are 4 special characters: the slash \f(CW\*(C`/\*(C'\fR, paired brackets \f(CW\*(C`[]\*(C'\fR,
the double-quote \f(CW\*(C`"\*(C'\fR and the backslash \f(CW\*(C`\e\*(C'\fR. They are needed and
explained in a logical order.
.PP
Path parts are divided by the slash \f(CW\*(C`/\*(C'\fR.
.PP
A path part can be extended by a filter with appending an expression
in brackets \f(CW\*(C`[]\*(C'\fR.
.PP
To contain slashes in hash keys, they can be surrounded by double
quotes \f(CW\*(C`"\*(C'\fR.
.PP
To contain double-quotes in hash keys they can be escaped with
backslash \f(CW\*(C`\e\*(C'\fR.
.PP
Backslashes in path parts don't need to be escaped, except before
escaped quotes (but see below on Backslash handling).
.PP
Filters of parts are already sufficiently divided by the brackets
\&\f(CW\*(C`[]\*(C'\fR. There is no need to handle special characters in them, not even
double-quotes. The filter expression just needs to be balanced on the
brackets.
.PP
So this is the order how to create paths:
.IP "1. backslash double-quotes that are part of the key" 4
.IX Item "1. backslash double-quotes that are part of the key"
.PD 0
.IP "2. put double-quotes around the resulting key" 4
.IX Item "2. put double-quotes around the resulting key"
.IP "3. append the filter expression after the key" 4
.IX Item "3. append the filter expression after the key"
.IP "4. separate several path parts with slashes" 4
.IX Item "4. separate several path parts with slashes"
.PD
.SS "Backslash handling"
.IX Subsection "Backslash handling"
If you know backslash in Perl strings, skip this paragraph, it should
be the same.
.PP
It is somewhat difficult to create a backslash directly before a
quoted double-quote.
.PP
Inside the DPath language the typical backslash rules of apply that
you already know from Perl \fBsingle quoted\fR strings. The challenge is
to specify such strings inside Perl programs where another layer of
this backslashing applies.
.PP
Without quotes it's all easy. Both a single backslash \f(CW\*(C`\e\*(C'\fR and a
double backslash \f(CW\*(C`\e\e\*(C'\fR get evaluated to a single backslash \f(CW\*(C`\e\*(C'\fR.
.PP
Extreme edge case by example: To specify a plain hash key like this:
.PP
.Vb 1
\& "EE\eE5\e"
.Ve
.PP
where the quotes are part of the key, you need to escape the quotes
and the backslash:
.PP
.Vb 1
\& \e"EE\eE5\e\e\e"
.Ve
.PP
Now put quotes around that to use it as DPath hash key:
.PP
.Vb 1
\& "\e"EE\eE5\e\e\e""
.Ve
.PP
and if you specify this in a Perl program you need to additionally
escape the backslashes (i.e., double their count):
.PP
.Vb 1
\& "\e"EE\eE5\e\e\e\e\e\e""
.Ve
.PP
As you can see, strangely, this backslash escaping is only needed on
backslashes that are not standing alone. The first backslash before
the first escaped double-quote is ok to be a single backslash.
.PP
All strange, isn't it? At least it's (hopefully) consistent with
something you know (Perl, Shell, etc.).
.SS "XPath idioms"
.IX Subsection "XPath idioms"
Here are some typical XPath use-cases that can be achieved with
Data::DPath, although a bit differently.
.PP
\fIAttribute access\fR
.IX Subsection "Attribute access"
.PP
In XPath it's quite common to use a filter with attributes like this:
.PP
.Vb 1
\& //AAA/BBB/*[@CCC="DDD"]
.Ve
.PP
A naive user could translate such a construct for Data::DPath like
this:
.PP
.Vb 1
\& //AAA/BBB/*[CCC eq "DDD"]
.Ve
.PP
except that it does not work. What works is this:
.PP
.Vb 1
\& //AAA/BBB/*[key eq "CCC" && value eq "DDD"]
.Ve
.SH "Iterator style"
.IX Header "Iterator style"
The \fIiterator style\fR approach is an alternative to the already
describe \fIget-all-results-at-once\fR approach. With it you iterate over
the results one by one and even allow relative sub searches on
each. The iterators use the Iterator \s-1API.\s0
.PP
Please note, that the iterators do \fBnot\fR save memory, they are just
holding the context to go step-by-step and to start subsequent
searches. Each iterator needs to evaluate its whole result set
first. So in fact with nested iterators your memory might even go up.
.SS "Basic usage by example"
.IX Subsection "Basic usage by example"
Initialize a DPath iterator on a data structure using:
.PP
.Vb 1
\& my $root = dpathi($data);
.Ve
.PP
Create a new iterator context, with the path relative to current
root context:
.PP
.Vb 1
\& my $affe_iter = $root\->isearch("//anywhere/affe");
.Ve
.PP
Iterate over affe results:
.PP
.Vb 5
\& while ($affe_iter\->isnt_exhausted)
\& {
\& my $affe_point = $affe_iter\->value; # next "affe" point
\& my $affe = $affe_point\->deref; # the actual "affe"
\& }
.Ve
.SS "Nested iterators example"
.IX Subsection "Nested iterators example"
This example is taken from the
Benchmark::Perl::Formance suite, where
the several plugins are allowed to provide their results anywhere
at any level down in the result hash.
.PP
When the results are printed we look for all keys \f(CW\*(C`Benchmark\*(C'\fR and
regenerate the path to each so we can name it accordingly, e.g.,
\&\f(CW\*(C`plugin.name.subname\*(C'\fR.
.PP
For this we need an iterator to get the single \f(CW\*(C`Benchmark\*(C'\fR points one
by one and evaluate the corresponding ancestors to fetch their hash
keys. Here is the code:
.PP
.Vb 12
\& my $benchmarks_iter = dpathi($results)\->isearch("//Benchmark");
\& while ($benchmarks_iter\->isnt_exhausted)
\& {
\& my $benchmark = $benchmarks_iter\->value;
\& my $ancestors_iter = $benchmark\->isearch ("/::ancestor");
\& while ($ancestors_iter\->isnt_exhausted)
\& {
\& my $ancestor = $ancestors_iter\->value;
\& print Dumper( $ancestor\->deref ); #(1)
\& print $ancestor\->first_point\->{attrs}{key}; #(2)
\& }
\& }
.Ve
.PP
Note that we have two iterators, the first one (\f(CW$benchmarks_iter\fR)
over the actual benchmark results and the second one
(\f(CW$ancestors_iter\fR) over the ancestors relative to one benchmark.
.PP
In line \fB#(1)\fR you can see that once you have the searched point,
here the ancestors, you get the actual data using
\&\f(CW\*(C`$iterator\->value\->deref\*(C'\fR.
.PP
The line \fB#(2)\fR is utilizing the internal data structure to find out
about the actual hash key under which the point is located. (There is
also an official \s-1API\s0 to that: \f(CW\*(C`$ancestor\->first_point\->attrs\->key\*(C'\fR,
but there it's necessary to check for undefined values before
calling the methods \fIattrs\fR and \fIkey\fR, so I went the easy way).
There's an equivalent attribute (\f(CW\*(C`idx\*(C'\fR) for the array index of a point
stored in an array.
.SH "INTERNAL METHODS"
.IX Header "INTERNAL METHODS"
To make pod coverage happy.
.SS "build_dpath"
.IX Subsection "build_dpath"
Prepares internal attributes for \fIdpath\fR.
.SS "build_dpathr"
.IX Subsection "build_dpathr"
Prepares internal attributes for \fIdpathr\fR.
.SS "build_dpathi"
.IX Subsection "build_dpathi"
Prepares internal attributes for \fIdpathi\fR.
.SH "AUTHOR"
.IX Header "AUTHOR"
Steffen Schwigon, \f(CW\*(C`\*(C'\fR
.SH "CONTRIBUTIONS"
.IX Header "CONTRIBUTIONS"
Florian Ragwitz (cleaner exports, \f(CW$_\fR scoping, general perl consultant)
.SH "SEE ALSO"
.IX Header "SEE ALSO"
There are other modules on \s-1CPAN\s0 which are related to finding elements
in data structures.
.IP "Data::Path" 4
.IX Item "Data::Path"
.IP "XML::XPathEngine" 4
.IX Item "XML::XPathEngine"
.IP "Tree::XPathEngine" 4
.IX Item "Tree::XPathEngine"
.IP "Class::XPath" 4
.IX Item "Class::XPath"
.IP "Hash::Path" 4
.IX Item "Hash::Path"
.SH "AUTHOR"
.IX Header "AUTHOR"
Steffen Schwigon
.SH "COPYRIGHT AND LICENSE"
.IX Header "COPYRIGHT AND LICENSE"
This software is copyright (c) 2019 by Steffen Schwigon.
.PP
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.