File Coverage

blib/lib/XML/LibXML/LazyMatcher.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package XML::LibXML::LazyMatcher;
2              
3 1     1   90092 use warnings;
  1         3  
  1         35  
4 1     1   6 use strict;
  1         2  
  1         34  
5              
6 1     1   4673 use XML::LibXML;
  0            
  0            
7              
8             =head1 NAME
9              
10             XML::LibXML::LazyMatcher - A simple XML matcher with lazy evaluation.
11              
12             =head1 VERSION
13              
14             Version 0.02
15              
16             =cut
17              
18             our $VERSION = '0.02';
19              
20              
21             =head1 SYNOPSIS
22              
23             my $dom = XML::LibXML->load_xml (string => "helloworld");
24             my $matcher;
25             my ($c2content, $c3content);
26             {
27             package XML::LibXML::LazyMatcher;
28             $matcher = M (root =>
29             C (M (c1 =>
30             C (M (c2 =>
31             sub {
32             $c2content = $_[0]->textContent;
33             return 1;
34             }),
35             M (c3 =>
36             sub {
37             $c3content = $_[0]->textContent;
38             return 1;
39             })))));
40             }
41             $matcher->($dom->documentElement);
42              
43             =head1 EXPORT
44              
45             None.
46              
47             =head1 SUBROUTINES/METHODS
48              
49             =head2 M (tagname => [sub_matcher, ...])
50              
51             Returns a matcher function. This returned function takes an
52             XML::LibXML::Node object as an argument. First, The matcher checks if
53             the tag name of the passed node is correct, then, applies the node to
54             all Cs. If all Cs return true value then
55             the C returns 1. Otherwise returns 0.
56              
57             You can define some action as a sub_matcher. A typical C
58             may be like this:
59              
60             sub {
61             my $node = shift; # $node should be a XML::LibXML::Node.
62            
63             return 0 unless is_valid($node);
64            
65             do_some_action($node);
66             return 1;
67             }
68              
69             =cut
70              
71             sub M {
72             my $tagname = shift;
73             my @matchers = @_;
74              
75             sub {
76             my $elem = shift;
77              
78             # warn "matching $tagname", $elem->nodeName;
79              
80             return 0 unless ($elem->nodeName eq $tagname);
81              
82             # warn "eating $tagname";
83              
84             for my $m (@matchers) {
85             if (ref ($m) eq "CODE") {
86             return 0 unless ($m->($elem)); # failure
87             } else {
88             die "invalid matcher";
89             }
90             }
91              
92             return 1;
93             };
94             }
95              
96             =head2 C (sub_matcher, ...)
97              
98             Creates a matcher function which tests all child nodes. If a
99             sub_matcher returns true value, then the C returns 1. Otherwise
100             returns 0.
101              
102             =cut
103              
104             sub C {
105             my $alternate = sub {
106             my @children = @_;
107              
108             sub {
109             my $elem = shift;
110              
111             for my $m (@children) {
112             return 1 if ($m->($elem));
113             }
114             return 0;
115             }
116             };
117              
118             my @children = @_;
119              
120             sub {
121             my $parent = shift;
122              
123             my $m = $alternate->(@children);
124             for (my $c = $parent->firstChild; $c; $c = $c->nextSibling) {
125             return 0 unless $m->($c);
126             }
127              
128             return 1;
129             }
130             }
131              
132             =head2 S (sub_matcher, ...)
133              
134             Creates a matcher function which test all child nodes sequentially.
135             Every child nodes is tested by the appropriate C
136             accordingly. The returned matcher fails if one of Cs
137             fails.
138              
139             Also, this matcher ignores empty text node for convenience.
140              
141             =cut
142              
143             sub S {
144             my @children = @_;
145              
146             sub {
147             my $parent = shift;
148              
149             for (my $c = $parent->firstChild; $c; $c = $c->nextSibling) {
150             next if ($c->nodeType == 3 && $c->textContent =~ /\s*/);
151             return 0 unless $#children >= 0 && shift (@children)->($c);
152             }
153              
154             return 0 if $#children >= 0;
155              
156             return 1;
157             }
158             }
159              
160             =head1 AUTHOR
161              
162             Toru Hisai, C<< >>
163              
164             =head1 BUGS
165              
166             Please report any bugs or feature requests to C, or through
167             the web interface at L. I will be notified, and then you'll
168             automatically be notified of progress on your bug as I make changes.
169              
170              
171              
172              
173             =head1 SUPPORT
174              
175             You can find documentation for this module with the perldoc command.
176              
177             perldoc XML::LibXML::LazyMatcher
178              
179              
180             You can also look for information at:
181              
182             =over 4
183              
184             =item * RT: CPAN's request tracker
185              
186             L
187              
188             =item * AnnoCPAN: Annotated CPAN documentation
189              
190             L
191              
192             =item * CPAN Ratings
193              
194             L
195              
196             =item * Search CPAN
197              
198             L
199              
200             =back
201              
202              
203             =head1 ACKNOWLEDGEMENTS
204              
205              
206             =head1 LICENSE AND COPYRIGHT
207              
208             Copyright 2010 Toru Hisai.
209              
210             This program is free software; you can redistribute it and/or modify it
211             under the terms of either: the GNU General Public License as published
212             by the Free Software Foundation; or the Artistic License.
213              
214             See http://dev.perl.org/licenses/ for more information.
215              
216              
217             =cut
218              
219             1; # End of XML::LibXML::LazyMatcher