summaryrefslogtreecommitdiff
path: root/lib/Tree/Transform/XSLTish/Optimizer.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Tree/Transform/XSLTish/Optimizer.pm')
-rw-r--r--lib/Tree/Transform/XSLTish/Optimizer.pm93
1 files changed, 93 insertions, 0 deletions
diff --git a/lib/Tree/Transform/XSLTish/Optimizer.pm b/lib/Tree/Transform/XSLTish/Optimizer.pm
new file mode 100644
index 0000000..d6449ed
--- /dev/null
+++ b/lib/Tree/Transform/XSLTish/Optimizer.pm
@@ -0,0 +1,93 @@
+package Tree::Transform::XSLTish::Optimizer;
+use strict;
+use warnings;
+use Tree::XPathEngine;
+use Scalar::Util qw(blessed looks_like_number reftype);
+
+my $NCName = qr{(?: [A-Za-z_] [\w\\.\\-]* )}x;
+my $QName = qr{(?: $NCName : )? $NCName}x;
+
+sub optimize_single_step {
+ my ($path) = @_;
+
+ my $s=$path->as_string;
+
+warn "single: $s\n";
+
+ if ($s =~ m{\A \( child:: ($QName) \) \z}x) {
+ return "self::$1",0,0,'any';
+ }
+
+ if ($s =~ m{\A \( /descendant:: ($QName) (?: /self::node\(\) )? \) \z}x) {
+ return "self::$1",0,0,'any';
+ }
+
+ return;
+}
+
+sub optimize_simple_path {
+ my ($path) = @_;
+
+ my $s=$path->as_string;
+ $s =~ s{/self::node\(\)/}{/}g;
+
+warn "simple: $s\n";
+
+ return unless $s =~ m{\A \(
+ (?: (?:child|/descendant) :: $QName )
+ (?: / (?:child|descendant) :: $QName )+
+ \) \z}x;
+
+ $s =~ s{/self::node\(\)/}{/}g;
+ my @steps= reverse grep {$_} split '/',substr($s,1,-1);
+
+ my @new=();
+
+ while (my $step = shift @steps) {
+ if ($step =~ m{^child::($QName)$}) {
+ if (@new) {
+ push @new,"parent::$1";
+ }
+ else {
+ push @new,"self::$1";
+ }
+ }
+ elsif ($step =~ m{^descendant::($QName)$}) {
+ if (@steps) {
+ push @new,"ancestor::$1";
+ }
+ else {
+ push @new,"parent::$1";
+ }
+ }
+ }
+
+ return unless @new;
+
+ return join('/',@new),0,0,'any';
+}
+
+my @rules = (
+ \&optimize_single_step,
+ \&optimize_simple_path,
+);
+
+my @flds=qw(opt_pattern min_depth max_depth expected_result);
+sub optimize {
+ my ($class,$rule) = @_;
+
+ return unless $rule->{match};
+
+ my $path = Tree::XPathEngine->new(NAME=>$QName)->_parse($rule->{match});
+
+ for my $opt (@rules) {
+ if (my @ret=$opt->($path)) {
+ @{$rule}{@flds}=@ret;
+ return;
+ }
+ }
+
+ return;
+}
+
+1;