line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package XML::Handler::Essex; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
$VERSION = 0.000_1; |
4
|
|
|
|
|
|
|
|
5
|
5
|
|
|
5
|
|
12803
|
use XML::Essex::Constants; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
38
|
|
6
|
5
|
|
|
5
|
|
29
|
use Scalar::Util qw( reftype ); |
|
5
|
|
|
|
|
29
|
|
|
5
|
|
|
|
|
929
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
#use Time::HiRes qw( time ); |
9
|
|
|
|
|
|
|
#sub warn { warn sprintf( "%.2f", time ), " ", @_; } |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
BEGIN { |
12
|
5
|
|
|
5
|
|
125
|
require XML::Handler::Essex::Threaded if threaded_essex; |
13
|
|
|
|
|
|
|
} |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 NAME |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
XML::Handler::Essex - Essex handler object (including XML::Filter::Essex) |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 SYNOPSIS |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
use XML::Handler::Essex; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my $h = XML::Handler::Essex->new( |
24
|
|
|
|
|
|
|
Main => sub { |
25
|
|
|
|
|
|
|
while ( get_chars ) { |
26
|
|
|
|
|
|
|
put uc; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 DESCRIPTION |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Defines (and exports, by default) C and C routines |
34
|
|
|
|
|
|
|
that allow an Essex handler and filter to pull events from the SAX |
35
|
|
|
|
|
|
|
stream. |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
Pulling is handled in one of two ways: the entire input document is |
38
|
|
|
|
|
|
|
buffered if a perl earlier than 5.8.0 is used, due to lack of |
39
|
|
|
|
|
|
|
multithreading, and threading is used in perls later than 5.8.0. |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Note that the event constructor functions (C, C, |
42
|
|
|
|
|
|
|
etc) are not exported by this module as they are from |
43
|
|
|
|
|
|
|
XML::Generator::Essex and XML::Filter::Essex; handlers rarely need |
44
|
|
|
|
|
|
|
these. |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Returns a "1" by default, use C to change. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=for test_script XML-Filter-Essex.t |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=cut |
51
|
|
|
|
|
|
|
|
52
|
5
|
|
|
5
|
|
3787
|
use XML::Essex::Base (); # Don't import things. |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
97
|
|
53
|
5
|
|
|
5
|
|
4961
|
use XML::Essex::Model (); |
|
5
|
|
|
|
|
17
|
|
|
5
|
|
|
|
|
310
|
|
54
|
5
|
|
|
5
|
|
37
|
use Carp (); |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
111
|
|
55
|
|
|
|
|
|
|
|
56
|
5
|
|
|
5
|
|
28
|
no warnings "once"; |
|
5
|
|
|
|
|
224
|
|
|
5
|
|
|
|
|
408
|
|
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
@ISA = qw( XML::Essex::Base ); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
@EXPORT = qw( |
61
|
|
|
|
|
|
|
isa |
62
|
|
|
|
|
|
|
next_event |
63
|
|
|
|
|
|
|
path |
64
|
|
|
|
|
|
|
type |
65
|
|
|
|
|
|
|
xeof |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
get |
68
|
|
|
|
|
|
|
on |
69
|
|
|
|
|
|
|
); |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# get_start_document |
72
|
|
|
|
|
|
|
# get_start_doc |
73
|
|
|
|
|
|
|
# |
74
|
|
|
|
|
|
|
# get_start_element |
75
|
|
|
|
|
|
|
# get_start_elt |
76
|
|
|
|
|
|
|
# get_end_element |
77
|
|
|
|
|
|
|
# get_end_elt |
78
|
|
|
|
|
|
|
# get_element |
79
|
|
|
|
|
|
|
# get_elt |
80
|
|
|
|
|
|
|
# |
81
|
|
|
|
|
|
|
# get_characters |
82
|
|
|
|
|
|
|
# get_chars |
83
|
|
|
|
|
|
|
#); |
84
|
|
|
|
|
|
|
|
85
|
5
|
|
|
5
|
|
26
|
use strict; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
372
|
|
86
|
5
|
|
|
5
|
|
7766
|
use NEXT; |
|
5
|
|
|
|
|
17071
|
|
|
5
|
|
|
|
|
146
|
|
87
|
5
|
|
|
5
|
|
11540
|
use XML::SAX::EventMethodMaker qw( compile_missing_methods sax_event_names ); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub new { |
90
|
|
|
|
|
|
|
my $proto = shift; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
return $proto->SUPER::new( @_ ) if ref $proto; |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
my $class = $proto; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
if ( threaded_essex ) { |
97
|
|
|
|
|
|
|
require XML::Handler::Essex::Threaded; |
98
|
|
|
|
|
|
|
$class .= "::Threaded"; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
return $class->SUPER::new( @_ ); |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub _init { ## Called by new() |
106
|
|
|
|
|
|
|
my $self = shift; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
$self->{PendingEvents} = []; |
109
|
|
|
|
|
|
|
$self->{Events} = []; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
$self->NEXT::_init( @_ ); |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub reset { ## called before main() by execute() |
116
|
|
|
|
|
|
|
my $self = shift; |
117
|
|
|
|
|
|
|
$self->{Result} = 1; |
118
|
|
|
|
|
|
|
## Hmmm, should we clear Events here? Can't clear |
119
|
|
|
|
|
|
|
## events in non-threaded mode. |
120
|
|
|
|
|
|
|
undef $self->{Dispatchers}; |
121
|
|
|
|
|
|
|
$self->NEXT::reset( @_ ); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub finish { ## called after main() by execute() |
126
|
|
|
|
|
|
|
my $self = shift; |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
my ( $ok, $x ) = @_; |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# die ref( $self ) . "::main() exited before end_document seen\n" |
131
|
|
|
|
|
|
|
# if $ok && $self->{InDocument}; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# In case we're also an XML::Generator::Essex, let it have |
134
|
|
|
|
|
|
|
# first crack at the result value. This sort of encodes |
135
|
|
|
|
|
|
|
# knowledge of the inheritance hierarchy for XML::Filter::Essex |
136
|
|
|
|
|
|
|
# in this code; it would be better to have an arbitration |
137
|
|
|
|
|
|
|
# scheme where there is a default result set, then a |
138
|
|
|
|
|
|
|
# downstream result, then a manually set result, with the |
139
|
|
|
|
|
|
|
# highest ranking one set winning (ie last in that list). |
140
|
|
|
|
|
|
|
# The current scheme, however, is BALGE. |
141
|
|
|
|
|
|
|
$DB::single=1; |
142
|
|
|
|
|
|
|
my ( $result_set, $result ) = $self->NEXT::finish( @_ ); |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
return ( $result_set, $result ) if $result_set; |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
unless ( $ok ) { |
147
|
|
|
|
|
|
|
if ( $x eq EOD . "\n" ) { |
148
|
|
|
|
|
|
|
return ( 1, $self->{Result} ); |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
die $x; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
return ( 1, $self->{Result} ); |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub _send_event_to_child { |
158
|
|
|
|
|
|
|
my $self = shift; |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
warn "Essex $self: queuing $_[0] for child\n" if debugging; |
161
|
|
|
|
|
|
|
push @{$self->{Events}}, @{$self->{PendingEvents}}, [ @_ ]; |
162
|
|
|
|
|
|
|
@{$self->{PendingEvents}} = (); |
163
|
|
|
|
|
|
|
# force scalar context to be consistent with the threaded case. |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
## There's a DESTROY in XML::Handler::Essex::Threaded |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# NOTE: returns \@event, whereas _send_event_to_child takes @event. |
170
|
|
|
|
|
|
|
# This is to speed the queue fudging that threaded_execute does on |
171
|
|
|
|
|
|
|
# start_document. |
172
|
|
|
|
|
|
|
sub _recv_event_from_parent { |
173
|
|
|
|
|
|
|
my $self = shift; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
my $event; |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
die EOD . "\n" |
178
|
|
|
|
|
|
|
if $self->{PendingResultType} eq "end_document"; |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
unless ( @{$self->{Events}} ) { |
181
|
|
|
|
|
|
|
if ( $self->{Reader} ) { |
182
|
|
|
|
|
|
|
do { |
183
|
|
|
|
|
|
|
$self->{Reader}->(); |
184
|
|
|
|
|
|
|
} until @{$self->{Events}}; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
else { |
187
|
|
|
|
|
|
|
Carp::croak "No XML events to process"; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
$event = $self->{Events}->[0]; |
192
|
|
|
|
|
|
|
my $event_type = $event->[0]; |
193
|
|
|
|
|
|
|
warn "Essex $self: got $event_type $event->[1] from parent\n" |
194
|
|
|
|
|
|
|
if debugging; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
shift @{$self->{Events}}; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
die $event_type . "\n" |
199
|
|
|
|
|
|
|
if $event_type eq BOD || $event_type eq EOD || $event_type eq SEPPUKU; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
if ( threaded_essex ) { |
202
|
|
|
|
|
|
|
## Set the default result for this event. |
203
|
|
|
|
|
|
|
@$self{ "PendingResultType", "PendingResult" } = |
204
|
|
|
|
|
|
|
( $event_type, "Essex: default result for $event_type" ); |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
return $event; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
# Hopefully, this handles inline set_document_locator events relatively |
211
|
|
|
|
|
|
|
# gracefully, by queueing them up until the next event arrives. This is |
212
|
|
|
|
|
|
|
# necessary because set_document_locator events can arrive *before* the |
213
|
|
|
|
|
|
|
# start_document, and we need to wait for the next event to see whether |
214
|
|
|
|
|
|
|
# to insert the BOD before the set_document_locator. This is all so that |
215
|
|
|
|
|
|
|
# the initial set_document_locator event(s) will arrive before the |
216
|
|
|
|
|
|
|
# start_document event in the main() routine, given that we need to |
217
|
|
|
|
|
|
|
# send the BOD psuedo event in case the main() routine is still running. |
218
|
|
|
|
|
|
|
sub set_document_locator { |
219
|
|
|
|
|
|
|
push @{shift->{PendingEvents}}, [ "set_document_locator", @_ ]; |
220
|
|
|
|
|
|
|
return "Essex: document locator queued"; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub end_document { |
225
|
|
|
|
|
|
|
my $self = shift; |
226
|
|
|
|
|
|
|
## Must send EOD after the end_document so that we get the end_document |
227
|
|
|
|
|
|
|
## result back first otherwise it would be lost because |
228
|
|
|
|
|
|
|
## _recv_event_from_parent does not send results back if there are any |
229
|
|
|
|
|
|
|
## other events in the queue. If this were not so, we could add a hack |
230
|
|
|
|
|
|
|
## here to queue up both end_document and EOD at once. |
231
|
|
|
|
|
|
|
my $r = $self->_send_event_to_child( "end_document", @_ ); |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
push @{$self->{Events}}, [ EOD ]; |
234
|
|
|
|
|
|
|
return $self->execute; |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
return $r; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
compile_missing_methods __PACKAGE__, <<'END_CODE', sax_event_names; |
240
|
|
|
|
|
|
|
#line 1 XML::Handler::Essex::() |
241
|
|
|
|
|
|
|
sub { |
242
|
|
|
|
|
|
|
shift->_send_event_to_child( "", @_ ); |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
END_CODE |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=head1 Exported Functions |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
These are exported by default, use the C |
250
|
|
|
|
|
|
|
exporting these. All of these act on $_ by default. |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=head2 Miscellaneous |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=over |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=item isa |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
get until isa "start_elt" and $_->name eq "foo"; |
259
|
|
|
|
|
|
|
$r = get until isa $r, "start_elt" and $_->name eq "foo"; |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
Returns true if the parameter is of the indicated object type. Tests $_ |
262
|
|
|
|
|
|
|
unless more than one parameter is passed. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Note the use of C instead of C<&&> to get paren-less C to |
265
|
|
|
|
|
|
|
behave as expected (this is a typical Perl idiom). |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=cut |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub isa { |
270
|
|
|
|
|
|
|
local $_ = shift if @_ >= 2; |
271
|
|
|
|
|
|
|
UNIVERSAL::isa( $_, "XML::Essex::Event" ) |
272
|
|
|
|
|
|
|
? $_->isa( @_ ) |
273
|
|
|
|
|
|
|
: UNIVERSAL::isa( $_, @_ ); |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=item path |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
get_start_elt until path eq "/path/to/foo:bar" |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
Returns the path to the current element as a string. |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=cut |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub path { |
285
|
|
|
|
|
|
|
my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
286
|
|
|
|
|
|
|
? shift |
287
|
|
|
|
|
|
|
: $XML::Essex::Base::self; |
288
|
|
|
|
|
|
|
return join "/", "", map $_->name, @{$self->{Stack}}; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=for import XML::Generator::Essex/put |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=item type |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
get until type eq "start_document"; |
296
|
|
|
|
|
|
|
$r = get until type $r eq "start_document"; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
Return the type name of the object. This is the class name with a |
300
|
|
|
|
|
|
|
leading XML::Essex:: stripped off. This is a wrapper around the |
301
|
|
|
|
|
|
|
event's C method. |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
Dies C if the parameter is not an object with a C method. |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=cut |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub type { |
308
|
|
|
|
|
|
|
local $_ = shift if @_; |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Carp::croak |
311
|
|
|
|
|
|
|
ref $_ || "a scalar", |
312
|
|
|
|
|
|
|
" is not an Essex event, cannot type() it\n" |
313
|
|
|
|
|
|
|
unless UNIVERSAL::can( $_, "type" ); |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
return $_->type( @_ ) |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=item xeof |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
Return TRUE if the last event read was an end_document event. |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=cut |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
sub xeof { |
325
|
|
|
|
|
|
|
my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
326
|
|
|
|
|
|
|
? shift |
327
|
|
|
|
|
|
|
: $XML::Essex::Base::self; |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
lock @{$self->{Events}} if threaded_essex; |
330
|
|
|
|
|
|
|
return @{$self->{Events}} && $self->{Events}->[0] eq EOD; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=item get |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
Gets an event or element from the incoming SAX input stream, puts it in |
336
|
|
|
|
|
|
|
C<$_> and returns it. Throws an exception when reading past the last |
337
|
|
|
|
|
|
|
event in a document. This exception is caught by XML::Essex and |
338
|
|
|
|
|
|
|
causes it to wait until the beginning of the next document and reenter |
339
|
|
|
|
|
|
|
the main routine. |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
Code Action |
342
|
|
|
|
|
|
|
======================= ======================================= |
343
|
|
|
|
|
|
|
get; Get the next SAX event, whatever it is. |
344
|
|
|
|
|
|
|
get "node()"; Get the next SAX event, whatever it is. |
345
|
|
|
|
|
|
|
get "*"; Get the next element, whatever its name. |
346
|
|
|
|
|
|
|
get "start-document::*"; Get the next start document event. |
347
|
|
|
|
|
|
|
get "end-document::*"; Get the next end document event. |
348
|
|
|
|
|
|
|
get "start-element::*"; Get the next start element event. |
349
|
|
|
|
|
|
|
get "end-element::*"; Get the next end element event. |
350
|
|
|
|
|
|
|
get "text()"; Get the next characters event. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Right now, only the expressions shown are supported. This is a |
353
|
|
|
|
|
|
|
limitation that will be lifted. There may be multiple characters |
354
|
|
|
|
|
|
|
events in a row, unlike xpath's text() matching expression. |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
See C and C functions and method (in |
357
|
|
|
|
|
|
|
L) for how to test what was just gotten. |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=cut |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
sub _get { |
362
|
|
|
|
|
|
|
my $self = shift; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
my ( $type, $data ) = @{$self->_recv_event_from_parent}; |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
my $event = bless \$data, "XML::Essex::Event::$type"; |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
unless ( $event->isa( "XML::Essex::Event" ) ) { |
369
|
|
|
|
|
|
|
no strict 'refs'; |
370
|
|
|
|
|
|
|
@{"XML::Essex::Event::${type}::ISA"} = qw( XML::Essex::Event ); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
pop @{$self->{Stack}} if $self->{PopNext}; |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
if ( $event->isa( "XML::Essex::Event::start_document" ) ) { |
376
|
|
|
|
|
|
|
$self->{Stack} = []; |
377
|
|
|
|
|
|
|
$self->{PopNext} = 0; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
elsif ( $event->isa( "XML::Essex::Event::start_element" ) ) { |
380
|
|
|
|
|
|
|
push @{$self->{Stack}}, $event; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
elsif ( $event->isa( "XML::Essex::Event::end_element" ) ) { |
383
|
|
|
|
|
|
|
# Delay popping so caller can see the end_element on the |
384
|
|
|
|
|
|
|
# stack if need be. |
385
|
|
|
|
|
|
|
$self->{PopNext} = 1; |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
else { |
388
|
|
|
|
|
|
|
$self->{PopNext} = 0; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
if ( $self->{Dispatchers} ) { |
392
|
|
|
|
|
|
|
$data->{__EssexEvent} = $event; |
393
|
|
|
|
|
|
|
for my $d ( @{$self->{Dispatchers}} ) { |
394
|
|
|
|
|
|
|
local $_; |
395
|
|
|
|
|
|
|
$d->$type( $data ); |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
# TODO: figure out a way to clean these up. |
398
|
|
|
|
|
|
|
# delete $data->{__EssexEvent}; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
return $event; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
sub get { |
406
|
|
|
|
|
|
|
my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
407
|
|
|
|
|
|
|
? shift |
408
|
|
|
|
|
|
|
: $XML::Essex::Base::self; |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
my ( $xpathlet ) = @_; |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
my $event_type; |
413
|
|
|
|
|
|
|
if ( ! defined $xpathlet || $xpathlet eq "node()" ) { |
414
|
|
|
|
|
|
|
return $_ = $self->_get; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
elsif ( $xpathlet eq "*" ) { |
417
|
|
|
|
|
|
|
return $self->get_element; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
elsif ( $xpathlet eq "start-document::*" ) { |
420
|
|
|
|
|
|
|
$event_type = "start_document"; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
elsif ( $xpathlet eq "end-document::*" ) { |
423
|
|
|
|
|
|
|
$event_type = "end_document"; |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
elsif ( $xpathlet eq "start-element::*" ) { |
426
|
|
|
|
|
|
|
$event_type = "start_element"; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
elsif ( $xpathlet eq "end-element::*" ) { |
429
|
|
|
|
|
|
|
$event_type = "end_element"; |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
elsif ( $xpathlet eq "text()" ) { |
432
|
|
|
|
|
|
|
$event_type = "characters"; |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
elsif ( $xpathlet eq "comment()" ) { |
435
|
|
|
|
|
|
|
$event_type = "comment"; |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
elsif ( $xpathlet eq "processing-instruction()" ) { |
438
|
|
|
|
|
|
|
$event_type = "processing_instruction"; |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
else { |
441
|
|
|
|
|
|
|
Carp::croak "Unsupported or invalid expression '$xpathlet'"; |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
my $event; |
445
|
|
|
|
|
|
|
while (1) { |
446
|
|
|
|
|
|
|
$event = $self->_get; |
447
|
|
|
|
|
|
|
last if $event->isa( $event_type ); |
448
|
|
|
|
|
|
|
$self->_skip_event( $event ); |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
$_ = $event; |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=item skip |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
Skips one event. This is what happens to events that are not returned |
457
|
|
|
|
|
|
|
from get(). For a handler, skip() does nothing (the event is ignored). |
458
|
|
|
|
|
|
|
For a Filter, the event is passed on the the handler. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=cut |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
sub _skip_event { |
463
|
|
|
|
|
|
|
## Ignore it by default. XML::Filter::Essex overloads this. |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
sub skip { |
467
|
|
|
|
|
|
|
my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
468
|
|
|
|
|
|
|
? shift |
469
|
|
|
|
|
|
|
: $XML::Essex::Base::self; |
470
|
|
|
|
|
|
|
$self->_skip_event( $self->_get ); |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=item next_event |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
Returns the event that the next call to get() will return. Dies if |
476
|
|
|
|
|
|
|
at xeof. Does not set $_. |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
NOTE: NOT YET IMPLEMENTED IN THREADED MODE. |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=cut |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
sub next_event { |
483
|
|
|
|
|
|
|
my $self = shift; |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
my ( $type, $data ) = do { |
486
|
|
|
|
|
|
|
Carp::croak "Essex: next_event() not yet implemented in threaded mode" |
487
|
|
|
|
|
|
|
if threaded_essex; |
488
|
|
|
|
|
|
|
lock @{$self->{Events}} if threaded_essex; |
489
|
|
|
|
|
|
|
@{$self->{Events}->[0]}; |
490
|
|
|
|
|
|
|
}; |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
my $e = bless \$data, "XML::Essex::Event::$type"; |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
unless ( $e->isa( "XML::Essex::Event" ) ) { |
495
|
|
|
|
|
|
|
no strict 'refs'; |
496
|
|
|
|
|
|
|
@{"XML::Essex::Event::${type}::ISA"} = qw( XML::Essex::Event ); |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
return $e; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
#=item get_start_document |
503
|
|
|
|
|
|
|
# |
504
|
|
|
|
|
|
|
#aka: get_start_doc |
505
|
|
|
|
|
|
|
# |
506
|
|
|
|
|
|
|
#Skips all events until the next start_document event. Perhaps only |
507
|
|
|
|
|
|
|
#useful in multi-document streams. |
508
|
|
|
|
|
|
|
# |
509
|
|
|
|
|
|
|
#=cut |
510
|
|
|
|
|
|
|
# |
511
|
|
|
|
|
|
|
#sub get_start_document { |
512
|
|
|
|
|
|
|
# my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
513
|
|
|
|
|
|
|
# ? shift |
514
|
|
|
|
|
|
|
# : $XML::Essex::Base::self; |
515
|
|
|
|
|
|
|
# |
516
|
|
|
|
|
|
|
# my $event; |
517
|
|
|
|
|
|
|
# do { |
518
|
|
|
|
|
|
|
# $event = $self->get; |
519
|
|
|
|
|
|
|
# } until $_->isa( "start_document" ); |
520
|
|
|
|
|
|
|
# |
521
|
|
|
|
|
|
|
# $_ = $event; |
522
|
|
|
|
|
|
|
#} |
523
|
|
|
|
|
|
|
# |
524
|
|
|
|
|
|
|
#*get_start_doc = \&get_start_document; |
525
|
|
|
|
|
|
|
# |
526
|
|
|
|
|
|
|
#=item get_end_document |
527
|
|
|
|
|
|
|
# |
528
|
|
|
|
|
|
|
#aka: get_end_doc |
529
|
|
|
|
|
|
|
# |
530
|
|
|
|
|
|
|
#Skips all events until the next end_document event. |
531
|
|
|
|
|
|
|
# |
532
|
|
|
|
|
|
|
#=cut |
533
|
|
|
|
|
|
|
# |
534
|
|
|
|
|
|
|
#sub get_end_document { |
535
|
|
|
|
|
|
|
# my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
536
|
|
|
|
|
|
|
# ? shift |
537
|
|
|
|
|
|
|
# : $XML::Essex::Base::self; |
538
|
|
|
|
|
|
|
# |
539
|
|
|
|
|
|
|
# my $event; |
540
|
|
|
|
|
|
|
# do { |
541
|
|
|
|
|
|
|
# $event = $self->get; |
542
|
|
|
|
|
|
|
# } until $_->isa( "end_document" ); |
543
|
|
|
|
|
|
|
# |
544
|
|
|
|
|
|
|
# $_ = $event; |
545
|
|
|
|
|
|
|
#} |
546
|
|
|
|
|
|
|
# |
547
|
|
|
|
|
|
|
#*get_end_doc = \&get_end_document; |
548
|
|
|
|
|
|
|
# |
549
|
|
|
|
|
|
|
#=item get_start_element |
550
|
|
|
|
|
|
|
# |
551
|
|
|
|
|
|
|
#aka: get_start_elt |
552
|
|
|
|
|
|
|
# |
553
|
|
|
|
|
|
|
#Skips all events until the next start_element event. |
554
|
|
|
|
|
|
|
# |
555
|
|
|
|
|
|
|
#=cut |
556
|
|
|
|
|
|
|
# |
557
|
|
|
|
|
|
|
#sub get_start_element{ |
558
|
|
|
|
|
|
|
# my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
559
|
|
|
|
|
|
|
# ? shift |
560
|
|
|
|
|
|
|
# : $XML::Essex::Base::self; |
561
|
|
|
|
|
|
|
# |
562
|
|
|
|
|
|
|
# my $event; |
563
|
|
|
|
|
|
|
# do { |
564
|
|
|
|
|
|
|
# $event = $self->_get; |
565
|
|
|
|
|
|
|
# } until $event->isa( "start_element" ); |
566
|
|
|
|
|
|
|
# |
567
|
|
|
|
|
|
|
# return $_ = $event; |
568
|
|
|
|
|
|
|
#} |
569
|
|
|
|
|
|
|
# |
570
|
|
|
|
|
|
|
#*get_start_elt = \&get_start_element; |
571
|
|
|
|
|
|
|
# |
572
|
|
|
|
|
|
|
#=item get_end_element |
573
|
|
|
|
|
|
|
# |
574
|
|
|
|
|
|
|
#aka: get_end_elt |
575
|
|
|
|
|
|
|
# |
576
|
|
|
|
|
|
|
#Skips all events until the next end_element event. Returns an |
577
|
|
|
|
|
|
|
#end_element object. |
578
|
|
|
|
|
|
|
# |
579
|
|
|
|
|
|
|
#=cut |
580
|
|
|
|
|
|
|
# |
581
|
|
|
|
|
|
|
#sub get_end_element { |
582
|
|
|
|
|
|
|
# my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
583
|
|
|
|
|
|
|
# ? shift |
584
|
|
|
|
|
|
|
# : $XML::Essex::Base::self; |
585
|
|
|
|
|
|
|
# |
586
|
|
|
|
|
|
|
# my $event; |
587
|
|
|
|
|
|
|
# do { |
588
|
|
|
|
|
|
|
# $event = $self->get; |
589
|
|
|
|
|
|
|
# } until $_->isa( "end_element" ); |
590
|
|
|
|
|
|
|
# |
591
|
|
|
|
|
|
|
# return $_ = $event; |
592
|
|
|
|
|
|
|
#} |
593
|
|
|
|
|
|
|
# |
594
|
|
|
|
|
|
|
#*get_end_elt = \&get_end_element; |
595
|
|
|
|
|
|
|
# |
596
|
|
|
|
|
|
|
#=item get_element |
597
|
|
|
|
|
|
|
# |
598
|
|
|
|
|
|
|
#aka: get_elt |
599
|
|
|
|
|
|
|
# |
600
|
|
|
|
|
|
|
# my $elt = get_elt; |
601
|
|
|
|
|
|
|
# |
602
|
|
|
|
|
|
|
#Skips all events until the next start_element event, then consumes it |
603
|
|
|
|
|
|
|
#and all events up to and including the matching eld_element event. |
604
|
|
|
|
|
|
|
#Returns an L object. |
605
|
|
|
|
|
|
|
# |
606
|
|
|
|
|
|
|
# my $start_element = get_start_elt; |
607
|
|
|
|
|
|
|
# my $elt = get_elt $start_element; |
608
|
|
|
|
|
|
|
# |
609
|
|
|
|
|
|
|
#Skips nothing; takes a start_element and uses it to create an element |
610
|
|
|
|
|
|
|
#object by reading all content and then matching end_element event |
611
|
|
|
|
|
|
|
#from the input stream. |
612
|
|
|
|
|
|
|
# |
613
|
|
|
|
|
|
|
#=cut |
614
|
|
|
|
|
|
|
# |
615
|
|
|
|
|
|
|
# |
616
|
|
|
|
|
|
|
sub get_element { |
617
|
|
|
|
|
|
|
my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
618
|
|
|
|
|
|
|
? shift |
619
|
|
|
|
|
|
|
: $XML::Essex::Base::self; |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
my $start_elt; |
622
|
|
|
|
|
|
|
if ( @_ ) { |
623
|
|
|
|
|
|
|
$start_elt = shift; |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
else { |
626
|
|
|
|
|
|
|
do { |
627
|
|
|
|
|
|
|
$start_elt = $self->_get; |
628
|
|
|
|
|
|
|
} until $start_elt->isa( "start_element" ); |
629
|
|
|
|
|
|
|
} |
630
|
|
|
|
|
|
|
my $elt = XML::Essex::Event::element->new( $start_elt ); |
631
|
|
|
|
|
|
|
while (1) { |
632
|
|
|
|
|
|
|
my $event = $self->_get; |
633
|
|
|
|
|
|
|
if ( $event->isa( "XML::Essex::Event::start_element" ) ) { |
634
|
|
|
|
|
|
|
$elt->_add_content( get_element $event ); |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
elsif ( $event->isa( "XML::Essex::Event::end_element" ) ) { |
637
|
|
|
|
|
|
|
$elt->_end_element( $event ); |
638
|
|
|
|
|
|
|
last; |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
else { |
641
|
|
|
|
|
|
|
$elt->_add_content( $event ); |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
return $_ = $elt; |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
#*get_elt = \&get_element; |
649
|
|
|
|
|
|
|
# |
650
|
|
|
|
|
|
|
#=item get_characters |
651
|
|
|
|
|
|
|
# |
652
|
|
|
|
|
|
|
#aka: get_chars |
653
|
|
|
|
|
|
|
# |
654
|
|
|
|
|
|
|
#Skips to the next characters event and returns it. |
655
|
|
|
|
|
|
|
# |
656
|
|
|
|
|
|
|
#=cut |
657
|
|
|
|
|
|
|
# |
658
|
|
|
|
|
|
|
#sub get_characters { |
659
|
|
|
|
|
|
|
# my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
660
|
|
|
|
|
|
|
# ? shift |
661
|
|
|
|
|
|
|
# : $XML::Essex::Base::self; |
662
|
|
|
|
|
|
|
# |
663
|
|
|
|
|
|
|
# my $event; |
664
|
|
|
|
|
|
|
# do { |
665
|
|
|
|
|
|
|
# $event = $self->get; |
666
|
|
|
|
|
|
|
# } until $_->isa( "characters" ); |
667
|
|
|
|
|
|
|
# |
668
|
|
|
|
|
|
|
# return $_ = $event; |
669
|
|
|
|
|
|
|
#} |
670
|
|
|
|
|
|
|
# |
671
|
|
|
|
|
|
|
#*get_chars = \&get_characters; |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
=item on |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
on( |
676
|
|
|
|
|
|
|
"start_document::*" => sub { warn "start of document reached" }, |
677
|
|
|
|
|
|
|
"end_document::*" => sub { warn "end of document reached" }, |
678
|
|
|
|
|
|
|
); |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=for TODO |
681
|
|
|
|
|
|
|
my $rule = on $pat1 => sub { ... }, ...; |
682
|
|
|
|
|
|
|
...time passes with rules in effect... |
683
|
|
|
|
|
|
|
disable_rule $rule; |
684
|
|
|
|
|
|
|
...time passes with rules I in effect... |
685
|
|
|
|
|
|
|
enable_rule $rule; |
686
|
|
|
|
|
|
|
...time passes with rules in effect again... |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
This declares that a rule should be in effect until the end of the |
689
|
|
|
|
|
|
|
document is reached. Each rule is a ( $pattern => $action ) pair where |
690
|
|
|
|
|
|
|
$pattern is an EventPath pattern (see |
691
|
|
|
|
|
|
|
L) and $action is a |
692
|
|
|
|
|
|
|
subroutine reference. |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
The Essex event object matched is passed in $_[1]. A reference to |
695
|
|
|
|
|
|
|
the current Essex handler is passed in $_[0]. This allows you to |
696
|
|
|
|
|
|
|
write libraries of functions that access the current Essex |
697
|
|
|
|
|
|
|
handler/filter/whatever. |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
Do not call get() in the actions, you'll confuse everything. That's |
700
|
|
|
|
|
|
|
a limitation that should be lifted one day. |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=for TODO or it is disabled. |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=for TODO Returns a handle that may be used to enable or disable all |
705
|
|
|
|
|
|
|
rules passed in. |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
For now, this must be called before the first get() for predictable |
708
|
|
|
|
|
|
|
results. |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
Rules remain in effect after the main() routine has exited to facilitate |
711
|
|
|
|
|
|
|
pure rule based processing. |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
=cut |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
## TODO: parse but don't compile rules; allow them to be compiled as |
716
|
|
|
|
|
|
|
## one large rule and added to a single X::F::D when the Reader |
717
|
|
|
|
|
|
|
## sub is run. |
718
|
|
|
|
|
|
|
sub _wrap_action { |
719
|
|
|
|
|
|
|
my ( $self, $action ) = @_; |
720
|
|
|
|
|
|
|
sub { |
721
|
|
|
|
|
|
|
local $XML::Essex::dispatcher = shift; |
722
|
|
|
|
|
|
|
$action->( $self, $_[0]->{__EssexEvent} ); |
723
|
|
|
|
|
|
|
}; |
724
|
|
|
|
|
|
|
} |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
sub on { |
728
|
|
|
|
|
|
|
my $self = @_ && UNIVERSAL::isa( $_[0], __PACKAGE__ ) |
729
|
|
|
|
|
|
|
? shift |
730
|
|
|
|
|
|
|
: $XML::Essex::Base::self; |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
return undef unless @_; |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
require XML::Filter::Dispatcher; |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
my @rules; |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
while ( @_ ) { |
739
|
|
|
|
|
|
|
my ( $pattern, $action ) = ( shift, shift ); |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
if ( ref $action eq "ARRAY" ) { |
742
|
|
|
|
|
|
|
## TODO: make this recursive |
743
|
|
|
|
|
|
|
my @actions = map { |
744
|
|
|
|
|
|
|
ref $_ eq "CODE" |
745
|
|
|
|
|
|
|
? _wrap_action( $self, $_ ) |
746
|
|
|
|
|
|
|
: $_; |
747
|
|
|
|
|
|
|
} @$action; |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
$action = \@actions; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
else { |
752
|
|
|
|
|
|
|
$action = _wrap_action( $self, $action ); |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
push @rules, ( $pattern => $action ); |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
push @{$self->{Dispatchers}}, XML::Filter::Dispatcher->new( |
759
|
|
|
|
|
|
|
Rules => \@rules, |
760
|
|
|
|
|
|
|
); |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
return undef; |
763
|
|
|
|
|
|
|
} |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
sub xvalue { $XML::Essex::dispatcher->xvalue( @_ ) } |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
sub xpush { XML::Filter::Dispatcher::xpush( @_ ) } |
768
|
|
|
|
|
|
|
sub xpop { XML::Filter::Dispatcher::xpop( @_ ) } |
769
|
|
|
|
|
|
|
sub xadd { XML::Filter::Dispatcher::xadd( @_ ) } |
770
|
|
|
|
|
|
|
sub xset { XML::Filter::Dispatcher::xset( @_ ) } |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=back |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
=head1 LIMITATIONS |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
=head1 COPYRIGHT |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
Copyright 2002, R. Barrie Slaymaker, Jr., All Rights Reserved |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=head1 LICENSE |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
You may use this module under the terms of the BSD, Artistic, oir GPL licenses, |
784
|
|
|
|
|
|
|
any version. |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
=head1 AUTHOR |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
Barrie Slaymaker |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
=cut |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
1; |