Data::Xslate - Templatize your data.
use Data::Xslate;
my $xslate = Data::Xslate->new();
my $output = $xslate->render( $input );
Given this input data structure:
{
color_names => ['red', 'blue', 'orange'],
email => {
message => 'Do you like the color <: $user.color_name :>?',
subject => 'Hello <: $user.name :>!',
to => '=user.email',
},
'email.from=' => 'george@example.com',
user => {
color_id => 2,
color_name => '<: node("color_names")[$color_id] :>',
email => '<: $login :>@example.com',
login => 'john',
name => 'John',
},
}
This data will be output:
{
color_names => ['red', 'blue', 'orange'],
email => {
from => 'george@example.com',
message => 'Do you like the color orange?',
subject => 'Hello John!',
to => 'john@example.com',
},
user => {
color_id => '2',
color_name => 'orange',
email => 'john@example.com',
login => 'john',
name => 'John',
},
}
This module provides a syntax for templatizing data structures.
The most powerful feature by far is templating, where you can use Text::Xslate in your values.
{
foo => 'green',
bar => 'It is <: $foo :>!',
}
# { foo=>'green', bar=>'It is green!' }
There is a lot you can do with this beyond simply including values from other keys:
{
prod => 1,
memcached_host => '<: if $prod { :>memcached.example.com<: } else { :>127.0.0.1<: } :>',
}
# { prod=>1, memcached_host=>'memcached.example.com' }
Values in arrays are also processed for templating:
{
ceo_name => 'Sara',
employees => [
'<: $ceo_name :>',
'Fred',
'Alice',
],
}
# {
# ceo_name => 'Sara',
# employees => [
# 'Sara',
# 'Fred',
# 'Alice',
# ],
# }
As well as using array values in a template:
{ foo=>'<: $bar.1 :>', bar=>[4,5,6] }
# { foo=>5, bar=>[4,5,6] }
Data structures of any arbitrary depth and complexity are handled correctly, and keys from any level can be referred to following the "Scope" rules.
Substituion allows you to retrieve a value from one key and use it
as the value for the current key. To do this your hash or array
value must start with the "substitution_tag" (defaults to =
):
{
foo => 14,
bar => '=foo',
}
# { foo=>14, bar=>14 }
Templating could be used instead of substitution:
{
foo => 14,
bar => '<: $foo :>',
}
But, templating only works with strings. Substitutions become vital when you want to substitute an array or hash:
{
foo => [1,2,3],
bar => '=foo',
}
# { foo=>[1,2,3], bar=>[1,2,3] }
The keys in substitution follow the "Scope" rules.
When setting a key value the key can point deeper into the structure by
separating keys with the "key_separator" (defaults to a dot, .
),
and ending the key with the "nested_key_tag" (defaults to =
).
Consider this:
{ a=>{ b=>1 }, 'a.b=' => 2 }
# { a=>{ b=>2 } }
So, nested keys are a way to set values in other data structures. This feature is very handy when you are merging data structures from different sources and one data structure will override a subset of values in the other.
When referring to other values in "Templating", "Substitution", or "Nested Keys" you are specifying a path made up of keys for this module to walk and find a value to retrieve.
So, when you specify a key path such as foo.bar
you are looking for a hash
with the key foo
who's value is a hash and then retrieving the value
of the bar
key in it.
Arrays are fully supported in these key paths so that if you specify
a key path such as bar.0
you are looking for a hash with the bar
key whose value is an array, and then the first value in the array is
fetched.
Note that the above examples assume that "key_separator" is a dot (.
),
the default.
When using either "Substitution" or "Templating" you specify a key to be acted on. This key is found using scope-aware rules where the key is searched for in a similar fashion to how you'd expect when dealing with lexical variables in programming.
For example, you can refer to a key in the same scope:
{ a=>1, b=>'=a' }
You may refer to a key in a lower scope:
{ a=>{ b=>1 }, c=>'=a.b' }
You may refer to a key in a higher scope:
{ a=>{ b=>'=c' }, c=>1 }
You may refer to a key in a higher scope that is nested:
{ a=>{ b=>'=c.d' }, c=>{ d=>1 } }
The logic behind this is pretty flexible, so more complex use cases will just work like you would expect.
If you'd rather avoid this scoping you can prepend any key with the "key_separator"
(defaults to a dot, .
), and it will be looked for at the root of the config data
only.
In the case of templating a special node
function is provided which
will allow you to retrieve an absolute key. For example these two lines
would do the same thing (printing out a relative key value):
<: $foo.bar :>
<: node("foo.bar") :>
But if you wanted to refer to an absolute key you'd have to do this:
<: node(".foo.bar") :>
Any arguments you pass to new
, which this class does not directly
handle, will be used when creating the underlying Text::Xslate object.
So, any arguments which Text::Xslate supports may be set. For example:
my $xslate = Data::Xslate->new(
substitution_tag => ']]', # A Data::Xslate argument.
verbose => 2, # A Text::Xslate argument.
);
The string to look for at the beginning of any string value which
signifies "Substitution". Defaults to =
. This is used in
data like this:
{ a=>{ b=>2 }, c => '=a.b' }
# { a=>{ b=>2 }, c => 2 }
The string to look for at the end of any key which signifies
"Nested Keys". Defaults to =
. This is used in data
like this:
{ a=>{ b=>2 }, 'a.c=' => 3 }
# { a=>{ b=>2, c=>3 } }
The string which will be used between keys. The default is a dot (.
)
which looks like this:
{ a=>{ b=>2 }, c => '=a.b' }
Whereas, for example, if you changed the key_separator
to a forward
slash it would look like this:
{ a=>{ b=>2 }, c => '=a/b' }
Which looks rather good with absolute keys:
{ a=>{ b=>2 }, c => '=/a/b' }
my $data_out = $xslate->render( $data_in );
Processes the data and returns new data. The passed in data is not modified.
Please submit bugs and feature requests to the Data-Xslate GitHub issue tracker:
https://github.com/bluefeet/Data-Xslate/issues
Aran Clary Deltac <bluefeet@gmail.com>
Mohammad S Anwar <mohammad.anwar@yahoo.com>
Thanks to ZipRecruiter for encouraging their employees to contribute back to the open source ecosystem. Without their dedication to quality software development this distribution would not exist.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.