Stefan Göbel
and 1 contributors

NAME

Data::SimplePath - Path-like access to complex data structures

VERSION

Version 0.005

SYNOPSIS

        # use default options
        use Data::SimplePath;

        # or change the default options for new objects:
        use Data::SimplePath 'AUTO_ARRAY'   => 0,
                             'REPLACE_LEAF' => 0,
                             'SEPARATOR'    => '#';

        # create new empty object with default options:
        my $a = Data::SimplePath -> new ();

        # create new object, set some initial content:
        my $b = Data::SimplePath -> new (
                { 'k1' => 'v1', 'k2' => ['a', { 'b' => 'c' }, 'd'] }
        );

        # same as above, but override some default options:
        my $c = Data::SimplePath -> new (
                { 'k1' => 'v1', 'k2' => ['a', { 'b' => 'c' }, 'd'] },
                { 'AUTO_ARRAY' => 0, 'SEPARATOR' => ':' }
        );

        # get the value 'c', ':' is the separator:
        my $x = $c -> get ('k2:1:b');

        # change the separator to '/':
        $c -> separator ('/');

        # enable automatic creation of arrays for numeric keys:
        $c -> auto_array (1);

        # create a new element:
        $c -> set ('k2/4/some key/0', 'new value');

        # the object will now contain the following data:
        #
        # {
        #   'k1' => 'v1',          # k1
        #   'k2' => [              # k2
        #     'a',                 # k2/0
        #     {                    # k2/1
        #       'b' => 'c'         # k2/1/b
        #     },
        #     'd',                 # k2/2
        #     undef,               # k2/3
        #     {                    # k2/4
        #       'some key' => [    # k2/4/some key
        #         'new value'      # k2/4/some/key/0
        #       ]
        #     }
        #   ]
        # }

DESCRIPTION

This module enables path-like (as in file system path) access to complex data structures of hashes and/or arrays. Not much more to say, see the SYNOPSIS example above...

Ok, a few more notes: The data structure may consist of hashes or arrays, to an arbitrary depth, and scalar values. You probably should not try to put blessed arrays or hashes in it, it may lead to unexpected behaviour in some situations.

The object containing the data structure exists only to help accessing the contents, you are free to modify the data in any way you want without the provided methods if you like, this will not break the object's behaviour.

The methods to access a certain element in the data structure need to know which element to act on (of course), there are two ways of specifying the element:

by key

The key is a single string, with parts of the path separated by the (object specific) separator. This is the recommended way to access an element. Note that the methods will normalize the provided key before it is used, see the normalize () method below.

by path

The path is an array containing the parts of the full path, it is basically the key split on the separator string. Empty (or undef) elements are usually ignored when a path is processed.

In the following documentation these two terms will be used as described above. Note that the root of the data structure is specified as an empty key (ie. he empty string '') or an empty array as path.

Similar Modules

There are a few modules with similar functionality are available: Data::Path and Data::DPath provide access to data structures using a more flexible and powerful (some may call it complicated) XPath like matching.

Data::SPath provides access to data structures using paths like Data::SimplePath does (including accessing arrayrefs with numeric keys, Data::Path and Data::DPath require special syntax for arrayrefs). Also, this module does support calling object methods with method names specified in the path, Data::SimplePath does not offer special treatment for objects.

However, unlike the aforementioned modules, Data::SimplePath not only provides read access to an existing data structure, it also provides methods to create, change or delete values in the data structure, using paths to specify the location, and automatically create nested structures if required.

So if you only need read access, see the documentation of the modules mentioned above, maybe one is better suited for your needs than Data::SimplePath.

CONFIGURATION

Each of the following configuration options can be set for every object either when creating the object (see new () and the example in the SYNOPSIS above) or later on with the methods auto_array (), replace_leaf () and separator () (see below). The default values for the options are mentioned below, and these defaults can be modified on import () time, as shown in the SYNOPSIS example above.

AUTO_ARRAY

If this option is set to a true value, arrays will be created for numeric keys:

        # suppose the data structure is an empty hashref:

        # with AUTO_ARRAY set to true:
        $h -> set ('a/0/b', 'value');

        # the data structure will now contain:
        # {
        #   'a' => [         # array created due to numeric key 0
        #     {
        #       'b' => 'value'
        #     }
        #   ]
        # }

        # same with AUTO_ARRAY set to false:
        $h -> set ('a/0/b', 'value');

        # the data structure will now contain:
        # {
        #   'a' => {         # everything's a hash
        #     '0' => {
        #       'b' => 'value'
        #     }
        #   }
        # }

This only works for newly created sub-lists (and thus this setting only changes how the set () method works), already existing hashes will not be changed, and elements in these hashes can be created, deleted and accessed with numeric keys as usual.

The default value of this option is 1 (enabled).

REPLACE_LEAF

If this option is true (default), an already existing scalar value in the data structure will be replaced by a hashref or arrayref automatically if you try to set () a value beneath its path:

        # suppose the data structure contains the following data:
        # {
        #   'key' => 'value'
        # }

        # with REPLACE_LEAF disabled:
        $h -> set ('key/subkey', 'value'); # this won't work
                                           # data is not changed

        # with REPLACE_LEAF enabled:
        $h -> set ('key/subkey', 'value'); # works

        # the data structure now contains:
        # {
        #   'key' => {
        #     'subkey' => 'value'
        #   }
        # }

Note that if this option is set to false, you can still assign a hashref (or arrayref) directly to the element itself:

        # same result as above:
        $h -> set ('key', {'subkey' => 'value'});

The default value of this option is 1 (enabled).

SEPARATOR

The string used to separate path elements in the key. This may be any string you like, just make sure the string itself is not contained in any actual keys of the hashes in the data structure, you will not be able to access such elements by key (access by path will still work, though).

The default value is '/'.

CLASS METHODS

new

        my $h = Data::SimplePath -> new ($initial, $config);

Creates a new Data::SimplePath object. If $initial is specified, which must be either a hashref or an arrayref, the contents of the object will be set to this data structure. $config may be used to set the configuration options for the object. It must be a hashref, valid keys are 'AUTO_ARRAY', 'REPLACE_LEAF' and 'SEPARATOR' (see the CONFIGURATION section for details). Note that you have to specify $initial if you want to set configuration options, even if you don't want to add any initial content, use undef in that case:

        my $h = Data::SimplePath -> new (undef, $config);

The initial hashref (or arrayref) will be used as is, every modification of the object will alter the original data:

        my $i = { 'a' => 'b' };
        my $h = Data::SimplePath -> new ($i);

        $h -> set ('a', 'c');
        print $i -> {'a'};      # will print the new value 'c'

Note that if $initial is defined a warning will be printed if it is not a hashref or an arraryref, see the WARNINGS section below. An invalid value for $config will cause no warning, the default settings will be used in this case.

OBJECT METHODS

auto_array, replace_leaf, separator

        # get current value
        my $aa = $h -> auto_array ();

        # set AUTO_ARRAY to 1, $aa will contain the old value:
        my $aa = $h -> auto_array (1);

        # the same syntax works for $h -> replace_leaf () and
        # $h -> separator ()

Get and/or set the object's AUTO_ARRAY, REPLACE_LEAF and SEPARATOR options. If no parameter is specified (or the paramter is undef) these methods will return the current value of the option, else the option will be set to the given (scalar) value and the old setting will be returned.

clone

        my $copy = $h -> clone ();

Creates a new Data::SimplePath object with the same contents and settings as the original one. Both objects are independent, ie. changing the contents (or settings) of one object does not effect the other one. (Storable's dclone () funtion is used to create the copy, see its documentation for details.)

    If you actually need more than one object to modify one data structure, either create the root reference first and pass it to the constructors of the different objects, or retrieve the root reference from an existing object with the data () method and pass it to the constructor. This may be useful for example if you need certain operations with AUTO_ARRAY enabled and others without the AUTO_ARRAY feature.

data

        my $data = $h -> data ();       # get a reference to the object contents
        my %data = $h -> data ();       # or - if it's a hash - put a copy in a hash
        my @data = $h -> data ();       # or put a copy in an array

Returns the object contents. In scalar context, the reference (either a hashref or an arrayref, depending on the data structure's root) will be returned - note that this is the actual data as used in the object, modifications will effect the object's data. In list context Storable's dclone () function will be used to create a copy of the data, the copy's root will be dereferenced and the resulting list will be returned. Please see Storable's documentation for limitations.

If there is no data, undef (or an empty list) will be returned.

does_exist

        if ($h -> does_exist ($key)) { ... }

Returns a true value if the element specified by the key exists in the data structure. If it does not exist, an undefined value will be returned. Instead of a key you may also specify an arrayref containing the path to the element to check. Using a key is recommended, though. The key will be normalized before it is used, see the normalize_key () method below.

    Actually, the value returned is a reference: if the element is itself a hashref or an arrayref, that reference is returned, in all other cases, a reference to the element is returned (unless the element does not exist, of course):

            # for a Data::SimplePath object with the following data:
            my $data = {
              'a' => {
                'a1' => 'scalar value for a1'
              },
              'b' => 'scalar value for b',
            };
    
            my $ref1 = $h -> does_exist ('a');
            my $ref2 = $h -> does_exist ('b');

    In this example $ref2 will be set to a reference to 'scalar value for b', changing this value is possible:

            $$ref2 = 'another value for b';

    $ref1 will contain the same reference as $data -> {'a'}, so you can change the contents of this (sub-) hashref, but not $data -> {'a'} itself.

    However, it is recommended to use the set () method to change the data structure, the behaviour of does_exist () may change in future versions.

get

        my $value = get ($key);

Returns the value of the element specified by the key $key. If the element does not exist an undefined value will be returned (which may be the actual value of the element, so better use the does_exist () method to check for existence if this is required). Instead of a key you may also specify an arrayref containing the path to the element to check. Using a key is recommended, though. The key will be normalized before it is used, see the normalize_key () method below.

If the element specified by the key (or path) is itself a hashref or an arrayref, this reference will be returned if the method is called in scalar context. In list context, it will be copied (using Storable's dclone () function) and the resulting (dereferenced) list will be returned. (See Storable's documentation for limitations.)

Note that if called with an empty key (or an empty path) get () works like the data () method, see above for details.

set

        my $success = $h -> set ($key, $value);

Sets the element specified by $key (may be an arrayref to the element's path, as usual) to the value $value. All required intermediate arrayrefs and/or hashrefs will be created:

        # starting with an empty arrayref as the data structure...

        $h -> set ('0/hash/0', 'value');

        # the data structure now contains:
        # [
        #   {                   # 0
        #     'hash' => [       # 0/hash
        #       'value'         # 0/hash/0
        #     ]
        #   }
        # ]

Note that in the example above the AUTO_ARRAY option is turned on. Another option that modifies the behaviour of set () is REPLACE_LEAF. See the CONFIGURATION section for a description of both options and some example code.

The method will return true if the operation was successful, and false if an error occured. If warnings are enabled (see the WARNINGS section below), a warning will be printed in case of an error.

If you specify an empty key or path, the value must be a hashref or arrayref and the object's data will be set to this new data structure.

remove

        my $removed = $h -> remove ($key);

Deletes the element specified by the key $key (you may also specify an arrayref containing the element's path in the data structure, usage of the key is recommended, though). The value of the removed element will be returned. If the element does not exist, undef will be returned. If the key (or path) is empty, the root reference will be returned and the data structure will be removed from the object.

This function basically works like Perl's delete () function for hashes and like the splice () function for arrays (removing one element and not adding anything to the array, of course).

path

        my @path = $h -> path ($key);

Returns an array containing the path elements for the specified key $key, ie. the normalized key (see normalize_key () below) split at the separator. Note that the resulting array may be empty.

key

        my $key = $h -> key (@path);

Joins the array with the current separator string and returns the resulting string. The example above can be written as:

        my $key = join $h -> separator (), @path;

Additionally, you may use this function with an arrayref, the following will return the same string as the first example:

        my $key = $h -> key (\@path);

Note that - unlike the path () function - no further processing is done. For example, if the array contains empty strings, the resulting string will contain multiple consecutive separators. Use normalize_key () to remove these if required.

normalize_key

        $key = $h -> normalize_key ($key);

Removes separator string(s) at the beginning and end of the specified key and replaces all occurrences of multiple consecutive separator strings in the key with a single one. For example, the normalized version of /some//path// (with the separator /) would be some/path.

WARNINGS

Data::SimplePath can print warnings if something is wrong, eg. if you try to access an array element with a non-numeric key or if you call the new () function with $initial being not a hashref or arrayref. If you enable warnings (ie. use warnings;) these warnings will be enabled, too. You may use the use warnings 'Data::SimplePath'; command to enable only the warnings of this module, and if you want to enable warnings in general but disable Data::SimplePath's ones, use no warnings 'Data::SimplePath';.

AUTHOR

Stefan Goebel

COPYRIGHT & LICENSE

Copyright (C) 2009 - 2013 Stefan Goebel, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.