| 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; |