Tree::Transform::XSLTish - transform tree data, like XSLT but in Perl
package MyTransform; use Tree::Transform::XSLTish; default_rules; tree_rule match => 'node[@id=5]', action => sub { return $_[0]->it->data(); }; package main; use My::Tree; my $tree= My::Tree->new(); # build something inside the tree my ($node5_data)=MyTransform->new->transform($tree);
Transforming an HTML document:
package HtmlTransform; use Tree::Transform::XSLTish; use strict; use warnings; engine_class 'XML::XPathEngine'; default_rules; tree_rule match => 'img[@alt="pick"]', action => sub { return $_[0]->it->findvalue('@src'); }; package main; use HTML::TreeBuilder::XPath; my $tree=HTML::TreeBuilder::XPath->new(); $tree->parse_file('mypage.html'); my $trans=HtmlTransform->new(); my ($image_srce)=$trans->transform($tree);
This module allows you to transform tree with Perl subroutines, just like XSLT does for XML documents.
It tries to model as closely as reasonable the semantic of XSLT.
By default, this module uses Tree::XPathEngine as its XPath engine, but you can use any other similar module, provided it implements the method findnodes with the same signature and meaning. XML::XPathEngine is a good candidate, or you could use XML::LibXML::XPathContext.
findnodes
The tree that you intend to manipulate must be implemented by classes that are compatible with the XPath engine; for example, Tree::DAG_Node::XPath if you use Tree::XPathEngine, or HTML::TreeBuilder::XPath if you use XML::XPathEngine.
tree_rule
tree_rule match => '//node_name', priority => 1, action => sub { ... };
This is the basic fuction to declare a transformation rule; it's equivalent to the template element is XSLT. It takes its parameters as a hash:
template
match
this is equivalent to the match attribute of template: it specifies the pattern for the nodes to which this rule applies.
From the XSLT spec:
A pattern is defined to match a node if and only if there is a possible context such that when the pattern is evaluated as an expression with that context, the node is a member of the resulting node-set. When a node is being matched, the possible contexts have a context node that is the node being matched or any ancestor of that node, and a context node list containing just the context node.
name
this is equivalent of the name attribute of template: it allows calling rules by name (see call_rule)
priority
this is equivalent of the priority attribute of template; currently the "default priority" as specified in the spec is not implemented
action
this code-ref will be called (in list context) when the rule is to be applied; it can return whatever you want: call_rule will return the result unchanged, apply_rules will return the list of all results of all the applied rules
The action code-ref will be called (by apply_rules or call_rule) with a Tree::Transform::XSLTish::Transformer object as its only parameter.
default_rules
This function will declare two rules that mimic the implicit rules of XSLT. It's equivalent to:
tree_rule match => '/', priority => 0, action => sub {$_[0]->apply_rules}; tree_rule match => '*', priority => 0, action => sub {$_[0]->apply_rules};
engine_class
engine_class 'XML::LibXML::XPathContext';
This function declares that the Tree::Transform::XSLTish::Transformer object returned by "new" should use this class to build its XPath engine.
This function is not exported by default: you have to use the module as:
use Tree::Transform::XSLTish ':engine';
engine_factory
engine_factory { My::XPath::Engine->new(params=>$whatever) };
This function declares that the Tree::Transform::XSLTish::Transformer object returned by "new" should call the passed code-ref to get its engine.
engine_class $classname is equivalent to engine_factory { $classname->new }.
engine_class $classname
engine_factory { $classname->new }
new
Returns a Tree::Transform::XSLTish::Transformer for the rules declared in this package.
Stylesheet import is implented with the usual Perl inheritance scheme. It should even work with Class::C3, since we use Class::MOP's class_precedence_list to get the list of inherited packages.
class_precedence_list
Engine factories are inherited, too, so you can extend a rules package without re-specifying the engine (you can, of course, override this and specify another one).
This module uses Sub::Exporter, see that module's documentation for things like renaming the imports.
It's slow. Right now each rule application is linear in the number of defined rules times the depth of the node being transformed. There are several ways to optimize this for most common cases (patches welcome), but I prefer to "make it correct, before making it fast"
Some sugaring with Devel::Declare could make everything look better
Gianni Ceccarelli <dakkar@thenautilus.net>
To install Tree::Transform::XSLTish, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Tree::Transform::XSLTish
CPAN shell
perl -MCPAN -e shell install Tree::Transform::XSLTish
For more information on module installation, please visit the detailed CPAN module installation guide.