Data-Utilities
view release on metacpan or search on metacpan
lib/Data/Transformator.pm view on Meta::CPAN
=item
extract data from an existing source : the transformation applies an
identity transformation (meaning copy the source structure to the
result), and during the process it uses selectors to select what data
from the source to copy to the result. The result automatically
inherits the structure from the source. This is called a selective
transformation. Use the key 'apply_identity_transformation' to enable
this mode.
=item
copy data from source to result : the transformation must be told what
the exact structure of the result is, before the result data can be
inserted into the result. This is called a constructive
transformation.
=back
It is possible to combine the two above in a single run, but that is
currently not tested enough to be sure it works alright, so be very
careful with that.
To use Data::Transformator, you have to
=over 2
=item 1
Construct the transformation with appropriate options:
=over 2
=item
Give the transformation a name, the name describes the purpose and/or
activities for the transformation.
=item
Tell the transformation if you want it to run as a selective
transformation or not (option name
'apply_identity_transformation'). Transformations can always be used
as constructive transformations.
=item
Tell the transformation how to find the data source.
=over 2
=item
Or the data source is literal content (option name 'contents').
=item
Or the data source is an object that implements a '->generate()'
method (option name 'source'). Transformations implement themselves a
'->generate()' method such that transformations can be cascaded
easily.
=back
=item
Tell the transformation what to transform (selection) and how to
transform (generate result). Data::Transformator uses code references
to generate results, of alternatively simpler things as explained
below. Whenever a code reference is used, it is called with the
arguments (self, context, current_content). Here, self is the
Data::Transformator object, context is an object that describes the
current context in the source data structure, current_content is the
generated result so far. $context->{path} contains a string with the
path to the current element. Compononents of the path are '/'
separated (unless overwritten with the constructor key 'separator').
This can be used for regular matching, and is especially handy using
'simple_transformators', see below.
Following keys are available to the constructor of
Data::Transformator:
=over 2
=item ->{simple_transformators}
Is an array of simple_transformators. Each simple_transformator is a
hash with a 'matcher' key that contains a regular expression that is
matched with the path of the currently selected element. If there is
a match, the selected subtree is put in the end result, under the
value of the 'key' element of the simple_transformator (creating a
hash in the result if necessary). If there is no 'key' element in the
simple_transformator, a 'code' element is looked for, which is a code
reference. The code is called to insert an appropriate result.
=item ->{transformators}
Is an array of transformators. Each transformator is code reference
that gets called as usual.
=item ->{apply_identity_transformation}
Contains a nested perl data structure that reflects the structure of
the source data. All data of the source that is selected by scalars
that evaluate to true in the content of apply_identity_transformation,
is inserted in the result. This key is very handy for selecting a set
of small portions of data, if the structure of the source is known
beforehand.
=back
Take a look at existing examples, e.g. in the unit tests of the
transformation engine.
=back
=item 2
Call the '->transform()' method on the transformator.
lib/Data/Transformator.pm view on Meta::CPAN
=head1 The transformation library
There is a small transformation library embedded in the
Data::Transformator. This library currently allows to
=over 2
=item
transform an array to be found somewhere in the data source to a hash
in the result set.
=item
transform a hash to be found somewhere in the data source to an array
in the result set.
=back
The library generates closures that work on the source data.
=head1 BACKGROUND
For the interested reader, please follow these reasoning steps:
=over 2
=item 1
A database query of a relational database (using tables and nested
tabled) can always be written out in one of the XML query dialects.
=item 2
Following from point 1: a database query can be expressed as a
structured query.
=item 3
A structured query can be summarized as
=over 2
=item 1
a selection of data from a preexisting data source.
=item 2
a structural simplification of the selection.
=back
=item 4
Combining the above: a query can be defined as applying (1) a
selective transformation and (2) a constructive transformation in
sequence to a preexisting data source. This is called cascaded
transformations.
=back
=head1 BUGS
Does only work with scalars, hashes and arrays. Support for
self-referential structures seems broken at the moment.
=head1 AUTHOR
Hugo Cornelis, hugo.cornelis@gmail.com
Copyright 2007 Hugo Cornelis.
This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 SEE ALSO
Data::Merger(3), Data::Comparator(3), Clone(3)
=cut
package Data::Transformator;
use strict;
use Data::Dumper;
my $debug_enabled = '0';
my $debug_context = '0';
my $debug_identity_transform = '0';
my $debug_identity_transform2 = '0';
my $debug_identity_transform3 = '0';
my $separator = "/";
sub _apply_identity_transformation
{
my $self = shift;
my $context = shift;
my $current = _context_get_current($context);
my $result_current = _context_get_current_result($context);
my $previous = _context_get_previous($context);
my $result_previous = _context_get_previous_result($context);
my $previous_type = $previous->{type};
lib/Data/Transformator.pm view on Meta::CPAN
# register name and count of current column
_context_register_current($context, $self, $component_key, $component, $count);
# increment count (before applying filters)
$count++;
#
# hash_filter return values :
#
# 0 : do not recurse.
# 1 : do recurse.
#
my $filter_data = 1;
if (exists $self->{hash_filter})
{
$filter_data
= &{$self->{hash_filter}}($context, $component_key, $component);
}
next if $filter_data eq 0;
# apply transformations
$self->_apply_transformations($context, $component_key, $component);
# transform component
$result->{$component_key} = $self->_transform_any($context, $component);
}
if (scalar keys %$contents eq 0)
{
# apply transformations
$self->_apply_transformations($context, undef, undef, );
}
# remove this column
_context_pop($context);
return($result);
}
#
# generate()
#
# Generate data resulting from this transformation. This is particularly
# useful when cascading transformations.
#
sub generate
{
my $self = shift;
# we are being used in a transformation cascade of some sort
return $self->transform();
}
sub new
{
my $proto = shift;
my $class = ref($proto) || $proto;
my $self = { @_ };
bless ($self, $class);
return $self;
}
sub transform
{
my $self = shift;
my $contents = shift;
# construct data to be transformed
my $data = $contents || $self->{contents};
# if there is a cascade from a related object
if (!$data
&& $self->{source})
{
# construct the data from the source
my $source = $self->{source};
$data = $source->generate();
}
# initialize the working context of the transformation
my $context = _context_create($self->{name}, $self->{context_separator}, );
# $self->{result} is a literal copy of the original, the
# construction of this copy will probably be removed later on for
# reasons of efficiency.
$self->{result} = $self->_transform_any($context, $data);
return $context->{result}->{content};
}
# small convenience library : common transforms of hashes and arrays.
#
# note that transformators simply copy the root of a sub-tree (with
# the sub-tree beneath), such that the filters applied to the sub-tree
# do not interfere anymore with the result. This is currently a
# deliberate choice for (1) ease of implementation, (2) performance..
# transform an array with given name to a hash with hash_keys as the array
# indices. Use an additional prefix to nest the result.
sub _lib_transform_array_to_hash
{
my $array_name = shift;
my $prefix = shift;
if (!$prefix)
{
$prefix = '';
}
my $array_name_quoted = quotemeta $array_name;
return
sub
{
my ($transform_data, $context, $contents) = @_;
# print STDERR $context->{path}, "\n";
# initialize library sub private variables
if ($context->{path} =~ m|[^/]/$array_name_quoted$|)
{
my $result = _context_get_main_result($context);
( run in 0.443 second using v1.01-cache-2.11-cpan-e1769b4cff6 )