line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package XML::Reader; |
2
|
|
|
|
|
|
|
$XML::Reader::VERSION = '0.65'; |
3
|
1
|
|
|
1
|
|
895
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
4
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
27
|
|
5
|
1
|
|
|
1
|
|
11
|
use Carp; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
58
|
|
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
469
|
use Acme::HTTP; |
|
1
|
|
|
|
|
2694
|
|
|
1
|
|
|
|
|
4944
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
set_timeout(10); |
10
|
|
|
|
|
|
|
set_redir_max(5); |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
require Exporter; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
15
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( all => [ qw(slurp_xml) ] ); |
16
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
17
|
|
|
|
|
|
|
our @EXPORT = qw(); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $use_module; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub import { |
22
|
1
|
|
|
1
|
|
9
|
my $calling_module = shift; |
23
|
|
|
|
|
|
|
|
24
|
1
|
|
|
|
|
1
|
my @plist; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
my $act_module; |
27
|
|
|
|
|
|
|
|
28
|
1
|
|
|
|
|
3
|
for my $sub (@_) { |
29
|
0
|
0
|
0
|
|
|
0
|
if ($sub eq 'XML::Parser' or $sub eq 'XML::Parsepp') { |
30
|
0
|
0
|
|
|
|
0
|
if (defined $act_module) { |
31
|
0
|
|
|
|
|
0
|
die "Duplicate module ('$act_module' and '$sub')"; |
32
|
|
|
|
|
|
|
} |
33
|
0
|
|
|
|
|
0
|
$act_module = $sub; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
else { |
36
|
0
|
|
|
|
|
0
|
push @plist, $sub; |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
1
|
50
|
|
|
|
3
|
if (defined $act_module) { |
41
|
0
|
|
|
|
|
0
|
activate($act_module); |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
1
|
|
|
|
|
98
|
XML::Reader->export_to_level(1, $calling_module, @plist); |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub activate { |
48
|
0
|
|
|
0
|
0
|
|
my ($mod) = @_; |
49
|
|
|
|
|
|
|
|
50
|
0
|
0
|
|
|
|
|
if ($mod eq 'XML::Parser') { |
|
|
0
|
|
|
|
|
|
51
|
0
|
|
|
|
|
|
require XML::Parser; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
elsif ($mod eq 'XML::Parsepp') { |
54
|
0
|
|
|
|
|
|
require XML::Parsepp; |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
else { |
57
|
0
|
|
|
|
|
|
die "Can't identify module = '$mod'"; |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
0
|
|
|
|
|
|
$use_module = $mod; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# deprecated functions (Klaus EICHNER, 28 Apr 2010, ver. 0.35): |
64
|
|
|
|
|
|
|
# only for backward compatibility |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# Klaus EICHNER, 28 Oct 2011, ver 0.39): |
67
|
|
|
|
|
|
|
# remove deprecated functions newhd() and rstem() |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# sub newhd { new(@_); } # newhd() is now deprecated, use new() instead |
70
|
|
|
|
|
|
|
# sub rstem { path(@_); } # rstem() is now deprecated, use path() instead |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub new { |
73
|
0
|
|
|
0
|
0
|
|
my $class = shift; |
74
|
0
|
|
|
|
|
|
my $self = {}; |
75
|
|
|
|
|
|
|
|
76
|
0
|
|
|
|
|
|
my %opt; |
77
|
0
|
0
|
|
|
|
|
%opt = %{$_[1]} if defined $_[1]; |
|
0
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
|
79
|
0
|
0
|
|
|
|
|
if (defined $opt{mode}) { |
80
|
0
|
|
|
|
|
|
my $flt; |
81
|
0
|
0
|
|
|
|
|
if ($opt{mode} eq 'attr-bef-start') { $flt = 2; } # attributes appear on seperate lines * before * . |
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
82
|
0
|
|
|
|
|
|
elsif ($opt{mode} eq 'attr-in-hash') { $flt = 3; } # no seperate lines for attributes, they appear in the hash %{$rdr->att_hash}. |
83
|
0
|
|
|
|
|
|
elsif ($opt{mode} eq 'pyx') { $flt = 4; } # pyx compatible way: delivers attributes, , characters, on individual lines. |
84
|
0
|
|
|
|
|
|
elsif ($opt{mode} eq 'branches') { $flt = 5; } # reads roots and branches: $rdr->rx, $rdr->rvalue and $rdr->rval |
85
|
|
|
|
|
|
|
else { |
86
|
0
|
|
|
|
|
|
croak "Failed assertion #0010 in XML::Reader->new: invalid mode = '$opt{mode}', expected 'attr-bef-start', 'attr-in-hash', 'pyx' or 'branches'"; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
0
|
0
|
|
|
|
|
if (defined $opt{filter}) { |
90
|
0
|
0
|
|
|
|
|
unless ($opt{filter} eq $flt) { |
91
|
0
|
|
|
|
|
|
croak "Failed assertion #0020 in XML::Reader->new: filter = '$opt{filter}' does not match mode = '$opt{mode}' (which corresponds to filter = '$flt')"; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
else { |
95
|
0
|
|
|
|
|
|
$opt{filter} = $flt; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
0
|
0
|
|
|
|
|
$opt{strip} = 1 unless defined $opt{strip}; |
100
|
0
|
0
|
|
|
|
|
$opt{filter} = 2 unless defined $opt{filter}; |
101
|
0
|
0
|
|
|
|
|
$opt{parse_pi} = 0 unless defined $opt{parse_pi}; |
102
|
0
|
0
|
|
|
|
|
$opt{parse_ct} = 0 unless defined $opt{parse_ct}; |
103
|
|
|
|
|
|
|
|
104
|
0
|
0
|
0
|
|
|
|
unless ($opt{filter} == 2 or $opt{filter} == 3 or $opt{filter} == 4 or $opt{filter} == 5) { |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
105
|
0
|
|
|
|
|
|
croak "Failed assertion #0030 in XML::Reader->new: filter is set to '$opt{filter}', but must be 2, 3, 4 or 5"; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
0
|
|
|
|
|
|
my @parser_opt; |
109
|
|
|
|
|
|
|
|
110
|
0
|
0
|
0
|
|
|
|
if (defined $opt{dupatt} and $opt{dupatt} ne '') { |
111
|
0
|
0
|
|
|
|
|
unless ($use_module eq 'XML::Parsepp') { |
112
|
0
|
|
|
|
|
|
croak "Failed assertion #0035 in XML::Reader->new: expected use qw(XML::Parsepp), but found use qw($use_module)"; |
113
|
|
|
|
|
|
|
} |
114
|
0
|
|
|
|
|
|
@parser_opt = (dupatt => $opt{dupatt}); |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
0
|
0
|
|
|
|
|
my $XmlParser = $use_module->new(@parser_opt) |
118
|
|
|
|
|
|
|
or croak "Failed assertion #0040 in XML::Reader->new: Can't create $use_module -> new(@parser_opt)"; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# The following references to the handler-functions from the XML::Parser/XML::Parsepp object will be |
121
|
|
|
|
|
|
|
# copied into the ExpatNB object during the later call to XML::Parser/XML::Parsepp->parse_start. |
122
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
$XmlParser->setHandlers( |
124
|
|
|
|
|
|
|
Start => \&handle_start, |
125
|
|
|
|
|
|
|
End => \&handle_end, |
126
|
|
|
|
|
|
|
Proc => \&handle_procinst, |
127
|
|
|
|
|
|
|
XMLDecl => \&handle_decl, |
128
|
|
|
|
|
|
|
Char => \&handle_char, |
129
|
|
|
|
|
|
|
Comment => \&handle_comment, |
130
|
|
|
|
|
|
|
); |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# We are trying to open the file (the filename is held in in $_[0]). If the filename |
133
|
|
|
|
|
|
|
# happens to be a reference to a scalar, then it is opened quite naturally as an |
134
|
|
|
|
|
|
|
# 'in-memory-file'. If the open fails, then we return failure from XML::Reader->new |
135
|
|
|
|
|
|
|
# and the calling program has to check $! to handle the failed call. |
136
|
|
|
|
|
|
|
# If, however, the filename is already a filehandle (i.e. ref($_[0]) eq 'GLOB'), then |
137
|
|
|
|
|
|
|
# we use that filehandle directly |
138
|
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
my $fh; |
140
|
|
|
|
|
|
|
|
141
|
0
|
0
|
|
|
|
|
if (ref($_[0]) eq 'GLOB') { |
142
|
0
|
|
|
|
|
|
$fh = $_[0]; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
else { |
145
|
0
|
0
|
|
|
|
|
if ($_[0] =~ m{\A https?:}xms) { |
146
|
0
|
0
|
|
|
|
|
$fh = Acme::HTTP->new($_[0]) |
147
|
|
|
|
|
|
|
or croak "Failed assertion #0042 in XML::Reader->new: Can't Acme::HTTP->new('$_[0]') because $@"; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
else { |
150
|
0
|
0
|
|
|
|
|
open $fh, '<', $_[0] or croak "Failed assertion #0045 in XML::Reader->new: Can't open < '$_[0]' because $!"; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Now we bless into XML::Reader, and we bless *before* creating the ExpatNB-object. |
155
|
|
|
|
|
|
|
# Thereby, to avoid a memory leak, we ensure that for each ExpatNB-object we call |
156
|
|
|
|
|
|
|
# XML::Reader->DESTROY when the object goes away. (-- by the way, we create that |
157
|
|
|
|
|
|
|
# ExpatNB-object by calling the XML::Parser/XML::Parsepp->parse_start method --) |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
bless $self, $class; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# Now we are ready to call XML::Parser/XML::Parsepp->parse_start -- XML::Parser/XML::Parsepp->parse_start() |
162
|
|
|
|
|
|
|
# returns an object of type XML::Parser/XML::Parsepp::ExpatNB. The XML::Parser/XML::Parsepp::ExpatNB object |
163
|
|
|
|
|
|
|
# is where all the heavy lifting happens. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# By calling the XML::Parser/XML::Parsepp::Expat->new method (-- XML::Parser::Expat is a super-class |
166
|
|
|
|
|
|
|
# of XML::Parser::ExpatNB --) we will have created a circular reference in |
167
|
|
|
|
|
|
|
# $self->{ExpatNB}{parser}. |
168
|
|
|
|
|
|
|
# |
169
|
|
|
|
|
|
|
# (-- unfortunately, the circular reference does not show up in Data::Dumper, there |
170
|
|
|
|
|
|
|
# is just an integer in $self->{ExpatNB}{parser} that represents a data-structure |
171
|
|
|
|
|
|
|
# within the C-function ParserCreate() --). |
172
|
|
|
|
|
|
|
# |
173
|
|
|
|
|
|
|
# See also the following line of code taken from XML::Parser::Expat->new: |
174
|
|
|
|
|
|
|
# |
175
|
|
|
|
|
|
|
# $args{Parser} = ParserCreate($self, $args{ProtocolEncoding}, $args{Namespaces}); |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# This means that, in order to avoid a memory leak, we have to break this circular |
178
|
|
|
|
|
|
|
# reference when we are done with the processing. The breaking of the circular reference |
179
|
|
|
|
|
|
|
# will be performed in XML::Reader->DESTROY, which calls XML::Parser::Expat->release. |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# This is an important moment (-- in terms of memory management, at least --). |
182
|
|
|
|
|
|
|
# XML::Parser/XML::Parsepp->parse_start creates an XML::Parser/XML::Parsepp::ExpatNB-object, which in turn generates |
183
|
|
|
|
|
|
|
# a circular reference (invisible with Data::Dumper). That circular reference will have to |
184
|
|
|
|
|
|
|
# be cleaned up when the XML::Reader-object goes away (see XML::Reader->DESTROY). |
185
|
|
|
|
|
|
|
|
186
|
0
|
0
|
0
|
|
|
|
$self->{ExpatNB} = $XmlParser->parse_start( |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
187
|
|
|
|
|
|
|
XR_Data => [], |
188
|
|
|
|
|
|
|
XR_Text => '', |
189
|
|
|
|
|
|
|
XR_Comment => '', |
190
|
|
|
|
|
|
|
XR_fh => $fh, |
191
|
|
|
|
|
|
|
XR_Att => [], |
192
|
|
|
|
|
|
|
XR_ProcInst => [], |
193
|
|
|
|
|
|
|
XR_Decl => {}, |
194
|
|
|
|
|
|
|
XR_Prv_SPECD => '', |
195
|
|
|
|
|
|
|
XR_Emit_attr => ($opt{filter} == 3 ? 0 : 1), |
196
|
|
|
|
|
|
|
XR_Split_up => ($opt{filter} == 4 || $opt{filter} == 5 ? 1 : 0), |
197
|
|
|
|
|
|
|
XR_Strip => $opt{strip}, |
198
|
|
|
|
|
|
|
XR_ParseInst => $opt{parse_pi}, |
199
|
|
|
|
|
|
|
XR_ParseComm => $opt{parse_ct}, |
200
|
|
|
|
|
|
|
) or croak "Failed assertion #0050 in subroutine XML::Reader->new: Can't create $use_module -> parse_start"; |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# for XML::Reader, version 0.21 (12-Sep-2009): |
203
|
|
|
|
|
|
|
# inject an {XR_debug} into $self->{ExpatNB}, if so requested by $opt{debug} |
204
|
|
|
|
|
|
|
|
205
|
0
|
0
|
|
|
|
|
if (exists $opt{debug}) { $self->{ExpatNB}{XR_debug} = $opt{debug}; } |
|
0
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# The instruction "XR_Data => []" (-- the 'XR_...' prefix stands for 'Xml::Reader...' --) |
208
|
|
|
|
|
|
|
# inside XML::Parser/XML::Parsepp->parse_start() creates an empty array $ExpatNB{XR_Data} = [] |
209
|
|
|
|
|
|
|
# inside the ExpatNB object. This array is the place where the handlers put their data. |
210
|
|
|
|
|
|
|
# |
211
|
|
|
|
|
|
|
# Likewise, the instructions "XR_Text => ''", "XR_Comment => ''", and "XR_fh => $fh" , etc... |
212
|
|
|
|
|
|
|
# create corresponding elements inside the $ExpatNB-object. |
213
|
|
|
|
|
|
|
|
214
|
0
|
0
|
|
|
|
|
$self->{sepchar} = defined $opt{sepchar} ? $opt{sepchar} : ''; |
215
|
0
|
|
|
|
|
|
$self->{filter} = $opt{filter}; |
216
|
0
|
0
|
|
|
|
|
$self->{using} = !defined($opt{using}) ? [] : ref($opt{using}) ? $opt{using} : [$opt{using}]; |
|
|
0
|
|
|
|
|
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# ******************************************************************************************** |
219
|
|
|
|
|
|
|
# The following lines have been disabled by Klaus Eichner, 30 Oct 2009 (for version 0.29) |
220
|
|
|
|
|
|
|
# ******************************************************************************************** |
221
|
|
|
|
|
|
|
# remove all spaces and then all leading and trailing '/', then put back a single leading '/' |
222
|
|
|
|
|
|
|
# for my $check (@{$self->{using}}) { |
223
|
|
|
|
|
|
|
# $check =~ s{\s}''xmsg; |
224
|
|
|
|
|
|
|
# $check =~ s{\A /+}''xms; |
225
|
|
|
|
|
|
|
# $check =~ s{/+ \z}''xms; |
226
|
|
|
|
|
|
|
# $check = '/'.$check; |
227
|
|
|
|
|
|
|
# } |
228
|
|
|
|
|
|
|
# ******************************************************************************************** |
229
|
|
|
|
|
|
|
|
230
|
0
|
|
|
|
|
|
$self->{bush} = []; |
231
|
0
|
|
|
|
|
|
$self->{rlist} = []; |
232
|
|
|
|
|
|
|
|
233
|
0
|
0
|
|
|
|
|
if ($self->{filter} == 5) { |
234
|
0
|
|
|
|
|
|
for my $object (@_[2..$#_]) { |
235
|
0
|
|
|
|
|
|
$object->{brna} = []; |
236
|
|
|
|
|
|
|
|
237
|
0
|
0
|
|
|
|
|
if (ref($object->{branch}) eq 'ARRAY') { |
238
|
0
|
|
|
|
|
|
for my $j (0..$#{$object->{branch}}) { |
|
0
|
|
|
|
|
|
|
239
|
0
|
|
|
|
|
|
$object->{branch}[$j] =~ s{\A ([^/\s])}{/$1}xms; |
240
|
|
|
|
|
|
|
|
241
|
0
|
|
|
|
|
|
$object->{brna}[$j] = []; |
242
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
my $b_level = 0; |
244
|
0
|
|
|
|
|
|
my $b_branch = $object->{branch}[$j]; |
245
|
0
|
|
|
|
|
|
$object->{branch}[$j] =~ s{\[ [^/\]]* \]}''xmsg; |
246
|
|
|
|
|
|
|
|
247
|
0
|
|
|
|
|
|
$b_branch =~ s{\A /+}''xms; |
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
|
for my $ele (split(m{/}xms, $b_branch)) { |
250
|
0
|
|
|
|
|
|
$b_level++; |
251
|
|
|
|
|
|
|
|
252
|
0
|
0
|
|
|
|
|
if ($ele =~ m{\[ \@ ([^\[\]=\s]+) = ['"] ([^'"]*) ['"] \]}xms) { |
253
|
0
|
|
|
|
|
|
push @{$object->{brna}[$j]}, [ $b_level - 1, $1, $2 ]; |
|
0
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
0
|
|
|
|
|
|
$object->{rota} = []; |
260
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
|
my $a_level = 0; |
262
|
0
|
|
|
|
|
|
my $a_root = $object->{root}; |
263
|
0
|
|
|
|
|
|
$object->{root} =~ s{\[ [^/\]]* \]}''xmsg; |
264
|
0
|
|
|
|
|
|
$a_root =~ s{\A /+}''xms; |
265
|
|
|
|
|
|
|
|
266
|
0
|
|
|
|
|
|
for my $ele (split(m{/}xms, $a_root)) { |
267
|
0
|
|
|
|
|
|
$a_level++; |
268
|
|
|
|
|
|
|
|
269
|
0
|
0
|
|
|
|
|
if ($ele =~ m{\[ \@ ([^\[\]=\s]+) = ['"] ([^'"]*) ['"] \]}xms) { |
270
|
0
|
|
|
|
|
|
push @{$object->{rota}}, [ $a_level - 1, $1, $2 ]; |
|
0
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
0
|
0
|
0
|
|
|
|
if ($object->{root} =~ m{\A // ([^/] .*) \z}xms |
275
|
|
|
|
|
|
|
or $object->{root} =~ m{\A ([^/] .*) \z}xms) { |
276
|
0
|
|
|
|
|
|
my $chunk = $1; |
277
|
0
|
|
|
|
|
|
push @{$self->{rlist}}, { |
|
0
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
root => undef, |
279
|
|
|
|
|
|
|
qr1 => qr{\A (.*) / \Q$chunk\E \z}xms, |
280
|
|
|
|
|
|
|
rota => $object->{rota}, |
281
|
|
|
|
|
|
|
qrfix => undef, |
282
|
|
|
|
|
|
|
branch => $object->{branch}, |
283
|
|
|
|
|
|
|
brna => $object->{brna}, |
284
|
|
|
|
|
|
|
}; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
else { |
287
|
0
|
|
|
|
|
|
push @{$self->{rlist}}, { |
|
0
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
root => $object->{root}, |
289
|
|
|
|
|
|
|
rota => $object->{rota}, |
290
|
|
|
|
|
|
|
qr1 => undef, |
291
|
|
|
|
|
|
|
qrfix => undef, |
292
|
|
|
|
|
|
|
branch => $object->{branch}, |
293
|
|
|
|
|
|
|
brna => $object->{brna}, |
294
|
|
|
|
|
|
|
}; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
#~ use Data::Dump; |
299
|
|
|
|
|
|
|
#~ dd \@_; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
$self->{plist} = []; |
303
|
0
|
|
|
|
|
|
$self->{alist} = []; |
304
|
0
|
|
|
|
|
|
$self->{path} = '/'; |
305
|
0
|
|
|
|
|
|
$self->{prefix} = ''; |
306
|
0
|
|
|
|
|
|
$self->{tag} = ''; |
307
|
0
|
|
|
|
|
|
$self->{value} = ''; |
308
|
0
|
|
|
|
|
|
$self->{att_hash} = {}; |
309
|
0
|
|
|
|
|
|
$self->{dec_hash} = {}; |
310
|
0
|
|
|
|
|
|
$self->{comment} = ''; |
311
|
0
|
|
|
|
|
|
$self->{pyx} = ''; |
312
|
0
|
|
|
|
|
|
$self->{rx} = 0; |
313
|
0
|
|
|
|
|
|
$self->{rvalue} = []; |
314
|
0
|
|
|
|
|
|
$self->{rresult} = []; |
315
|
0
|
|
|
|
|
|
$self->{proc} = ''; |
316
|
0
|
|
|
|
|
|
$self->{type} = '?'; |
317
|
0
|
|
|
|
|
|
$self->{is_start} = 0; |
318
|
0
|
|
|
|
|
|
$self->{is_end} = 0; |
319
|
0
|
|
|
|
|
|
$self->{is_decl} = 0; |
320
|
0
|
|
|
|
|
|
$self->{is_proc} = 0; |
321
|
0
|
|
|
|
|
|
$self->{is_comment} = 0; |
322
|
0
|
|
|
|
|
|
$self->{is_text} = 0; |
323
|
0
|
|
|
|
|
|
$self->{is_attr} = 0; |
324
|
0
|
|
|
|
|
|
$self->{is_value} = 0; |
325
|
0
|
|
|
|
|
|
$self->{level} = 0; |
326
|
0
|
|
|
|
|
|
$self->{item} = ''; |
327
|
|
|
|
|
|
|
|
328
|
0
|
|
|
|
|
|
return $self; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
# path() and value() are the two main functions: |
332
|
|
|
|
|
|
|
# ********************************************** |
333
|
|
|
|
|
|
|
|
334
|
0
|
|
|
0
|
1
|
|
sub path { $_[0]{path}; } |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub value { |
337
|
0
|
0
|
|
0
|
1
|
|
if ($_[0]{filter} == 5) { |
338
|
0
|
0
|
|
|
|
|
ref $_[0]{rvalue} eq 'ARRAY' ? @{$_[0]{rvalue}} : $_[0]{rvalue}; |
|
0
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
else { |
341
|
0
|
|
|
|
|
|
$_[0]{value}; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
0
|
|
|
0
|
1
|
|
sub tag { $_[0]{tag}; } |
346
|
0
|
|
|
0
|
1
|
|
sub attr { $_[0]{attr}; } |
347
|
0
|
|
|
0
|
1
|
|
sub att_hash { $_[0]{att_hash}; } |
348
|
0
|
|
|
0
|
1
|
|
sub dec_hash { $_[0]{dec_hash}; } |
349
|
0
|
|
|
0
|
1
|
|
sub type { $_[0]{type}; } |
350
|
0
|
|
|
0
|
1
|
|
sub level { $_[0]{level}; } |
351
|
0
|
|
|
0
|
1
|
|
sub prefix { $_[0]{prefix}; } |
352
|
0
|
|
|
0
|
1
|
|
sub comment { $_[0]{comment}; } |
353
|
0
|
|
|
0
|
1
|
|
sub pyx { $_[0]{pyx}; } |
354
|
0
|
|
|
0
|
1
|
|
sub rx { $_[0]{rx}; } |
355
|
0
|
|
|
0
|
1
|
|
sub rvalue { $_[0]{rvalue}; } |
356
|
0
|
|
|
0
|
1
|
|
sub proc_tgt { $_[0]{proc_tgt}; } |
357
|
0
|
|
|
0
|
1
|
|
sub proc_data { $_[0]{proc_data}; } |
358
|
0
|
|
|
0
|
1
|
|
sub is_decl { $_[0]{is_decl}; } |
359
|
0
|
|
|
0
|
1
|
|
sub is_start { $_[0]{is_start}; } |
360
|
0
|
|
|
0
|
1
|
|
sub is_proc { $_[0]{is_proc}; } |
361
|
0
|
|
|
0
|
1
|
|
sub is_comment { $_[0]{is_comment}; } |
362
|
0
|
|
|
0
|
1
|
|
sub is_text { $_[0]{is_text}; } |
363
|
0
|
|
|
0
|
1
|
|
sub is_attr { $_[0]{is_attr}; } |
364
|
0
|
|
|
0
|
1
|
|
sub is_value { $_[0]{is_value}; } |
365
|
0
|
|
|
0
|
1
|
|
sub is_end { $_[0]{is_end}; } |
366
|
|
|
|
|
|
|
|
367
|
0
|
|
|
0
|
0
|
|
sub NB_data { $_[0]{ExpatNB}{XR_Data}; } |
368
|
0
|
|
|
0
|
0
|
|
sub NB_fh { $_[0]{ExpatNB}{XR_fh}; } |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
sub iterate { |
371
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
{ |
374
|
0
|
0
|
|
|
|
|
if ($self->{filter} == 5) { |
|
0
|
|
|
|
|
|
|
375
|
0
|
|
|
|
|
|
my $res = shift @{$self->{rresult}}; |
|
0
|
|
|
|
|
|
|
376
|
0
|
0
|
|
|
|
|
if ($res) { |
377
|
0
|
|
|
|
|
|
$self->{rx} = $res->[0]; |
378
|
0
|
|
|
|
|
|
$self->{rvalue} = $res->[1]; |
379
|
0
|
|
|
|
|
|
return 1; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
|
my $token = $self->get_token; |
384
|
0
|
0
|
|
|
|
|
unless (defined $token) { |
385
|
0
|
|
|
|
|
|
return; |
386
|
|
|
|
|
|
|
} |
387
|
|
|
|
|
|
|
|
388
|
0
|
0
|
|
|
|
|
if ($token->found_start_tag) { |
389
|
0
|
|
|
|
|
|
push @{$self->{plist}}, $token->extract_tag; |
|
0
|
|
|
|
|
|
|
390
|
0
|
|
|
|
|
|
push @{$self->{alist}}, {}; |
|
0
|
|
|
|
|
|
|
391
|
0
|
|
|
|
|
|
redo; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
0
|
0
|
|
|
|
|
if ($token->found_end_tag) { |
395
|
0
|
|
|
|
|
|
pop @{$self->{plist}}; |
|
0
|
|
|
|
|
|
|
396
|
0
|
|
|
|
|
|
pop @{$self->{alist}}; |
|
0
|
|
|
|
|
|
|
397
|
0
|
|
|
|
|
|
redo; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
0
|
|
|
|
|
|
my $prv_SPECD = $token->extract_prv_SPECD; |
401
|
0
|
|
|
|
|
|
my $nxt_SPECD = $token->extract_nxt_SPECD; |
402
|
|
|
|
|
|
|
|
403
|
0
|
|
|
|
|
|
$self->{rx} = 0; |
404
|
0
|
|
|
|
|
|
$self->{rvalue} = []; |
405
|
|
|
|
|
|
|
|
406
|
0
|
0
|
|
|
|
|
if ($token->found_text) { |
|
|
0
|
|
|
|
|
|
407
|
0
|
|
|
|
|
|
my $text = $token->extract_text; |
408
|
0
|
|
|
|
|
|
my $comment = $token->extract_comment; |
409
|
|
|
|
|
|
|
|
410
|
0
|
|
|
|
|
|
my $proc_tgt = ''; |
411
|
0
|
|
|
|
|
|
my $proc_data = ''; |
412
|
0
|
0
|
|
|
|
|
if (@{$token->extract_proc} == 2) { |
|
0
|
|
|
|
|
|
|
413
|
0
|
|
|
|
|
|
$proc_tgt = ${$token->extract_proc}[0]; |
|
0
|
|
|
|
|
|
|
414
|
0
|
|
|
|
|
|
$proc_data = ${$token->extract_proc}[1]; |
|
0
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
0
|
0
|
|
|
|
|
$self->{is_decl} = $prv_SPECD eq 'D' ? 1 : 0; |
418
|
0
|
0
|
|
|
|
|
$self->{is_start} = $prv_SPECD eq 'S' ? 1 : 0; |
419
|
0
|
0
|
|
|
|
|
$self->{is_proc} = $prv_SPECD eq 'P' ? 1 : 0; |
420
|
0
|
0
|
|
|
|
|
$self->{is_comment} = $prv_SPECD eq 'C' ? 1 : 0; |
421
|
0
|
0
|
|
|
|
|
$self->{is_end} = $nxt_SPECD eq 'E' ? 1 : 0; |
422
|
|
|
|
|
|
|
|
423
|
0
|
|
|
|
|
|
$self->{is_text} = 1; |
424
|
0
|
|
|
|
|
|
$self->{is_attr} = 0; |
425
|
|
|
|
|
|
|
|
426
|
0
|
|
|
|
|
|
$self->{path} = '/'.join('/', @{$self->{plist}}); |
|
0
|
|
|
|
|
|
|
427
|
0
|
|
|
|
|
|
$self->{attr} = ''; |
428
|
0
|
|
|
|
|
|
$self->{value} = $text; |
429
|
0
|
|
|
|
|
|
$self->{comment} = $comment; |
430
|
0
|
|
|
|
|
|
$self->{proc_tgt} = $proc_tgt; |
431
|
0
|
|
|
|
|
|
$self->{proc_data} = $proc_data; |
432
|
0
|
|
|
|
|
|
$self->{level} = @{$self->{plist}}; |
|
0
|
|
|
|
|
|
|
433
|
0
|
0
|
|
|
|
|
$self->{tag} = @{$self->{plist}} ? ${$self->{plist}}[-1] : ''; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
434
|
0
|
|
|
|
|
|
$self->{type} = 'T'; |
435
|
0
|
|
|
|
|
|
$self->{att_hash} = {@{$token->extract_attr}}; |
|
0
|
|
|
|
|
|
|
436
|
0
|
|
|
|
|
|
$self->{dec_hash} = {@{$token->extract_decl}}; |
|
0
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
|
438
|
0
|
|
|
|
|
|
for (keys %{$self->{att_hash}}) { |
|
0
|
|
|
|
|
|
|
439
|
0
|
|
|
|
|
|
$self->{alist}[-1]{$_} = $self->{att_hash}{$_}; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
elsif ($token->found_attr) { |
443
|
0
|
|
|
|
|
|
my $key = $token->extract_attkey; |
444
|
0
|
|
|
|
|
|
my $val = $token->extract_attval; |
445
|
|
|
|
|
|
|
|
446
|
0
|
|
|
|
|
|
$self->{is_decl} = 0; |
447
|
0
|
|
|
|
|
|
$self->{is_start} = 0; |
448
|
0
|
|
|
|
|
|
$self->{is_proc} = 0; |
449
|
0
|
|
|
|
|
|
$self->{is_comment} = 0; |
450
|
0
|
|
|
|
|
|
$self->{is_end} = 0; |
451
|
|
|
|
|
|
|
|
452
|
0
|
|
|
|
|
|
$self->{is_text} = 0; |
453
|
0
|
|
|
|
|
|
$self->{is_attr} = 1; |
454
|
|
|
|
|
|
|
|
455
|
0
|
|
|
|
|
|
$self->{path} = '/'.join('/', @{$self->{plist}}).'/@'.$key; |
|
0
|
|
|
|
|
|
|
456
|
0
|
|
|
|
|
|
$self->{attr} = $key; |
457
|
0
|
|
|
|
|
|
$self->{value} = $val; |
458
|
0
|
|
|
|
|
|
$self->{comment} = ''; |
459
|
0
|
|
|
|
|
|
$self->{proc_tgt} = ''; |
460
|
0
|
|
|
|
|
|
$self->{proc_data} = ''; |
461
|
0
|
|
|
|
|
|
$self->{level} = @{$self->{plist}} + 1; |
|
0
|
|
|
|
|
|
|
462
|
0
|
|
|
|
|
|
$self->{tag} = '@'.$key; |
463
|
0
|
|
|
|
|
|
$self->{type} = '@'; |
464
|
0
|
|
|
|
|
|
$self->{att_hash} = {}; |
465
|
0
|
|
|
|
|
|
$self->{dec_hash} = {}; |
466
|
|
|
|
|
|
|
|
467
|
0
|
|
|
|
|
|
$self->{alist}[-1]{$key} = $val; |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
else { |
470
|
0
|
|
|
|
|
|
croak "Failed assertion #0060 in subroutine XML::Reader->iterate: Found data type '".$token->[0]."'"; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
# for {filter => 4 or 5} |
474
|
|
|
|
|
|
|
# - promote $self->{type} -- from 'T'/'@' to any of the following codes: 'D', '?', 'S', 'E', '#', 'T', '@' |
475
|
|
|
|
|
|
|
# - update $self->{is_text} |
476
|
|
|
|
|
|
|
# - setup $self->{pyx} |
477
|
|
|
|
|
|
|
|
478
|
0
|
0
|
0
|
|
|
|
if ($self->{filter} == 4 or $self->{filter} == 5) { |
479
|
0
|
0
|
|
|
|
|
if ($self->{type} eq '@') { $self->{pyx} = 'A'.$self->{attr}.' '.$self->{value}; } |
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
480
|
0
|
|
|
|
|
|
elsif ($self->{is_decl}) { my $dc = $self->{dec_hash}; |
481
|
0
|
|
|
|
|
|
$self->{type} = 'D'; $self->{pyx} = '?xml'.join('', map {" $_='$dc->{$_}'"} sort {$b cmp $a} keys %$dc); } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
482
|
0
|
|
|
|
|
|
elsif ($self->{is_proc}) { $self->{type} = '?'; $self->{pyx} = '?'.$self->{proc_tgt}.' '.$self->{proc_data}; } |
|
0
|
|
|
|
|
|
|
483
|
0
|
|
|
|
|
|
elsif ($self->{is_start}) { $self->{type} = 'S'; $self->{pyx} = '('.$self->{tag}; } |
|
0
|
|
|
|
|
|
|
484
|
0
|
|
|
|
|
|
elsif ($self->{is_end}) { $self->{type} = 'E'; $self->{pyx} = ')'.$self->{tag}; } |
|
0
|
|
|
|
|
|
|
485
|
0
|
|
|
|
|
|
elsif ($self->{is_comment}) { $self->{type} = '#'; $self->{pyx} = '#'.$self->{comment}; } |
|
0
|
|
|
|
|
|
|
486
|
0
|
|
|
|
|
|
else { $self->{type} = 'T'; $self->{pyx} = '-'.$self->{value}; } |
|
0
|
|
|
|
|
|
|
487
|
0
|
|
|
|
|
|
$self->{pyx} =~ s{\\}'\\\\'xmsg; # replace each backslash by a double-backslash |
488
|
0
|
|
|
|
|
|
$self->{pyx} =~ s{\t}'\\t'xmsg; # replace tabs by a literal "\\t" |
489
|
0
|
|
|
|
|
|
$self->{pyx} =~ s{\n}'\\n'xmsg; # replace newlines by a literal "\\n" |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
# update $self->{is_text} |
492
|
0
|
0
|
|
|
|
|
$self->{is_text} = $self->{type} eq 'T' ? 1 : 0; |
493
|
|
|
|
|
|
|
} |
494
|
|
|
|
|
|
|
else { |
495
|
0
|
|
|
|
|
|
$self->{pyx} = undef; |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
|
498
|
0
|
0
|
0
|
|
|
|
$self->{is_value} = ($self->{is_text} || $self->{is_attr}) ? 1 : 0; |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
# for {filter => 5} check roots |
501
|
0
|
0
|
|
|
|
|
if ($self->{filter} == 5) { |
502
|
0
|
|
|
|
|
|
for my $r (0..$#{$self->{rlist}}) { |
|
0
|
|
|
|
|
|
|
503
|
0
|
|
|
|
|
|
my $param = $self->{rlist}[$r]; |
504
|
|
|
|
|
|
|
|
505
|
0
|
|
|
|
|
|
my $twig; |
506
|
|
|
|
|
|
|
my $border; |
507
|
|
|
|
|
|
|
|
508
|
0
|
|
|
|
|
|
my $root; |
509
|
0
|
|
|
|
|
|
my $rotn = 0; |
510
|
|
|
|
|
|
|
|
511
|
0
|
0
|
|
|
|
|
if (defined $param->{root}) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
512
|
0
|
|
|
|
|
|
$root = $param->{root}; |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
elsif (defined $param->{qrfix}) { |
515
|
0
|
|
|
|
|
|
$root = $param->{qrfix}; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
elsif (defined $param->{qr1}) { |
518
|
0
|
0
|
|
|
|
|
if ($self->{path} =~ $param->{qr1}) { my $prf = $1; |
|
0
|
|
|
|
|
|
|
519
|
0
|
|
|
|
|
|
$rotn = () = $prf =~ m{/}xmsg; |
520
|
0
|
|
|
|
|
|
$root = $self->{path}; |
521
|
0
|
|
|
|
|
|
$param->{qrfix} = $root; |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
0
|
0
|
|
|
|
|
if (defined $root) { |
526
|
0
|
0
|
|
|
|
|
if ($root eq '/') { |
527
|
0
|
0
|
|
|
|
|
if (@{$self->{plist}} == 1) { |
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
528
|
0
|
|
|
|
|
|
$twig = $self->{path}; |
529
|
0
|
|
|
|
|
|
$border = 1; |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
elsif (@{$self->{plist}} > 1) { |
532
|
0
|
|
|
|
|
|
$twig = $self->{path}; |
533
|
0
|
|
|
|
|
|
$border = 0; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
else { |
537
|
0
|
0
|
|
|
|
|
if ($self->{path} eq $root) { |
|
|
0
|
|
|
|
|
|
538
|
0
|
|
|
|
|
|
$twig = '/'; |
539
|
0
|
|
|
|
|
|
$border = 1; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
elsif (substr($self->{path}, 0, length($root) + 1) eq $root.'/') { |
542
|
0
|
|
|
|
|
|
$twig = substr($self->{path}, length($root)); |
543
|
0
|
|
|
|
|
|
$border = 0; |
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
0
|
0
|
|
|
|
|
next unless defined $twig; |
549
|
|
|
|
|
|
|
|
550
|
0
|
|
|
|
|
|
my $block = 0; |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
#~ if (@{$param->{rota}}) { |
553
|
|
|
|
|
|
|
#~ use Data::Dump; |
554
|
|
|
|
|
|
|
#~ print "\nDeb-0010: param->{rota}:\n"; |
555
|
|
|
|
|
|
|
#~ dd $param->{rota}; |
556
|
|
|
|
|
|
|
#~ print "\nDeb-0020: self->{alist}:\n"; |
557
|
|
|
|
|
|
|
#~ dd $self->{alist}; |
558
|
|
|
|
|
|
|
#~ } |
559
|
|
|
|
|
|
|
|
560
|
0
|
|
|
|
|
|
for (@{$param->{rota}}) { |
|
0
|
|
|
|
|
|
|
561
|
0
|
|
|
|
|
|
my ($offset, $attr, $val) = ($_->[0] + $rotn, $_->[1], $_->[2]); |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
#~ print "Deb-0030: offset = $offset ($_->[0] + $rotn), attr = '$attr', val = '$val'\n"; |
564
|
|
|
|
|
|
|
|
565
|
0
|
|
|
|
|
|
my $e = $self->{alist}[$offset]; |
566
|
|
|
|
|
|
|
|
567
|
0
|
0
|
|
|
|
|
unless ($e) { |
568
|
|
|
|
|
|
|
#~ print "Deb-0100: Block-01\n"; |
569
|
0
|
|
|
|
|
|
$block++; |
570
|
0
|
|
|
|
|
|
next; |
571
|
|
|
|
|
|
|
} |
572
|
|
|
|
|
|
|
|
573
|
0
|
|
|
|
|
|
my $v = $e->{$attr}; |
574
|
|
|
|
|
|
|
|
575
|
0
|
0
|
|
|
|
|
unless (defined $v) { |
576
|
|
|
|
|
|
|
#~ print "Deb-0110: Block-02\n"; |
577
|
0
|
|
|
|
|
|
$block++; |
578
|
0
|
|
|
|
|
|
next; |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
|
581
|
0
|
0
|
|
|
|
|
unless ($v eq $val) { |
582
|
|
|
|
|
|
|
#~ print "Deb-0120: Block-03\n"; |
583
|
0
|
|
|
|
|
|
$block++; |
584
|
0
|
|
|
|
|
|
next; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
#~ print "Deb-0150: Good...\n"; |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
0
|
0
|
|
|
|
|
next if $block; |
591
|
|
|
|
|
|
|
|
592
|
0
|
|
|
|
|
|
my $bran; |
593
|
|
|
|
|
|
|
|
594
|
0
|
0
|
|
|
|
|
if ($root eq '/') { |
595
|
0
|
|
|
|
|
|
$bran = 0; |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
else { |
598
|
0
|
|
|
|
|
|
$bran = () = $root =~ m{/}xmsg; |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
|
601
|
0
|
0
|
|
|
|
|
if (ref $param->{branch}) { # here we have an array of branches... |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
602
|
0
|
0
|
0
|
|
|
|
if ($border and $self->{is_start}) { |
603
|
0
|
|
|
|
|
|
$self->{bush}[$r] = []; |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
|
606
|
0
|
0
|
|
|
|
|
if ($self->{is_value}) { |
607
|
0
|
|
|
|
|
|
for my $i (0..$#{$param->{branch}}) { |
|
0
|
|
|
|
|
|
|
608
|
0
|
0
|
|
|
|
|
if ($param->{branch}[$i] eq $twig) { |
609
|
|
|
|
|
|
|
|
610
|
0
|
|
|
|
|
|
my $block = 0; |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
#~ if (@{$param->{brna}[$i]}) { |
613
|
|
|
|
|
|
|
#~ use Data::Dump; |
614
|
|
|
|
|
|
|
#~ print "\nDeb-0010: param->{brna}[$i]:\n"; |
615
|
|
|
|
|
|
|
#~ dd $param->{brna}[$i]; |
616
|
|
|
|
|
|
|
#~ print "\nDeb-0020: self->{alist}:\n"; |
617
|
|
|
|
|
|
|
#~ dd $self->{alist}; |
618
|
|
|
|
|
|
|
#~ } |
619
|
|
|
|
|
|
|
|
620
|
0
|
|
|
|
|
|
for (@{$param->{brna}[$i]}) { |
|
0
|
|
|
|
|
|
|
621
|
0
|
|
|
|
|
|
my ($offset, $attr, $val) = ($_->[0] + $bran, $_->[1], $_->[2]); |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
#~ print "Deb-0030: offset = $offset ($_->[0] + $bran), attr = '$attr', val = '$val'\n"; |
624
|
|
|
|
|
|
|
|
625
|
0
|
|
|
|
|
|
my $e = $self->{alist}[$offset]; |
626
|
|
|
|
|
|
|
|
627
|
0
|
0
|
|
|
|
|
unless ($e) { |
628
|
|
|
|
|
|
|
#~ print "Deb-0100: Block-01\n"; |
629
|
0
|
|
|
|
|
|
$block++; |
630
|
0
|
|
|
|
|
|
next; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
0
|
|
|
|
|
|
my $v = $e->{$attr}; |
634
|
|
|
|
|
|
|
|
635
|
0
|
0
|
|
|
|
|
unless (defined $v) { |
636
|
|
|
|
|
|
|
#~ print "Deb-0110: Block-02\n"; |
637
|
0
|
|
|
|
|
|
$block++; |
638
|
0
|
|
|
|
|
|
next; |
639
|
|
|
|
|
|
|
} |
640
|
|
|
|
|
|
|
|
641
|
0
|
0
|
|
|
|
|
unless ($v eq $val) { |
642
|
|
|
|
|
|
|
#~ print "Deb-0120: Block-03\n"; |
643
|
0
|
|
|
|
|
|
$block++; |
644
|
0
|
|
|
|
|
|
next; |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
#~ print "Deb-0150: Good...\n"; |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
|
650
|
0
|
0
|
|
|
|
|
unless ($block) { |
651
|
0
|
|
|
|
|
|
my $ref = \$self->{bush}[$r][$i]; |
652
|
0
|
0
|
|
|
|
|
$$ref .= (defined $$ref ? $self->{sepchar} : '').$self->{value}; |
653
|
|
|
|
|
|
|
} |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
elsif ($param->{branch} eq '+') { # collect PYX array, addition for ver 0.39 (Klaus Eichner, 28th Oct 2011) |
659
|
0
|
0
|
0
|
|
|
|
if ($border and $self->{is_start}) { |
660
|
0
|
|
|
|
|
|
$self->{bush}[$r] = []; |
661
|
|
|
|
|
|
|
} |
662
|
0
|
|
|
|
|
|
push @{$self->{bush}[$r]}, $self->{pyx}; |
|
0
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
elsif ($param->{branch} eq '*') { # collect pure XML data, addition for ver 0.34 (Klaus Eichner, 26th Apr 2010) |
665
|
0
|
0
|
0
|
|
|
|
if ($border and $self->{is_start}) { |
666
|
0
|
|
|
|
|
|
$self->{bush}[$r] = ''; |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
|
669
|
0
|
|
|
|
|
|
my $element = ''; |
670
|
0
|
0
|
|
|
|
|
if ($self->{is_decl}) { |
671
|
0
|
|
|
|
|
|
$element .= ''; |
672
|
0
|
|
|
|
|
|
for my $key (sort keys %{$self->{dec_hash}}) { |
|
0
|
|
|
|
|
|
|
673
|
0
|
|
|
|
|
|
my $kval = $self->{dec_hash}{$key}; |
674
|
0
|
|
|
|
|
|
$kval =~ s{&}'&'xmsg; |
675
|
0
|
|
|
|
|
|
$kval =~ s{'}'''xmsg; |
676
|
0
|
|
|
|
|
|
$kval =~ s{<}'<'xmsg; |
677
|
0
|
|
|
|
|
|
$kval =~ s{>}'>'xmsg; |
678
|
0
|
|
|
|
|
|
$element .= qq{ $key='$kval'}; |
679
|
|
|
|
|
|
|
} |
680
|
0
|
|
|
|
|
|
$element .= '?>'; |
681
|
|
|
|
|
|
|
} |
682
|
0
|
0
|
|
|
|
|
if ($self->{is_start}) { |
683
|
0
|
|
|
|
|
|
$element .= '<'.$self->{tag}; |
684
|
0
|
|
|
|
|
|
for my $key (sort keys %{$self->{att_hash}}) { |
|
0
|
|
|
|
|
|
|
685
|
0
|
|
|
|
|
|
my $kval = $self->{att_hash}{$key}; |
686
|
0
|
|
|
|
|
|
$kval =~ s{&}'&'xmsg; |
687
|
0
|
|
|
|
|
|
$kval =~ s{'}'''xmsg; |
688
|
0
|
|
|
|
|
|
$kval =~ s{<}'<'xmsg; |
689
|
0
|
|
|
|
|
|
$kval =~ s{>}'>'xmsg; |
690
|
0
|
|
|
|
|
|
$element .= qq{ $key='$kval'}; |
691
|
|
|
|
|
|
|
} |
692
|
0
|
|
|
|
|
|
$element .= '>'; |
693
|
|
|
|
|
|
|
} |
694
|
0
|
0
|
|
|
|
|
if ($self->{is_proc}) { |
695
|
0
|
|
|
|
|
|
my $tgt = $self->{proc_tgt}; |
696
|
0
|
|
|
|
|
|
my $dat = $self->{proc_data}; |
697
|
0
|
|
|
|
|
|
for ($tgt, $dat) { |
698
|
0
|
|
|
|
|
|
s{&}'&'xmsg; |
699
|
0
|
|
|
|
|
|
s{'}'''xmsg; |
700
|
0
|
|
|
|
|
|
s{<}'<'xmsg; |
701
|
0
|
|
|
|
|
|
s{>}'>'xmsg; |
702
|
|
|
|
|
|
|
} |
703
|
0
|
|
|
|
|
|
$element .= "$tgt $dat?>"; |
704
|
|
|
|
|
|
|
} |
705
|
0
|
0
|
|
|
|
|
if ($self->{is_text}) { |
706
|
0
|
|
|
|
|
|
my $tval = $self->{value}; |
707
|
0
|
0
|
|
|
|
|
if ($tval ne '') { |
708
|
0
|
|
|
|
|
|
$tval =~ s{&}'&'xmsg; |
709
|
0
|
|
|
|
|
|
$tval =~ s{<}'<'xmsg; |
710
|
0
|
|
|
|
|
|
$tval =~ s{>}'>'xmsg; |
711
|
0
|
|
|
|
|
|
$element .= $tval; |
712
|
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
} |
714
|
0
|
0
|
|
|
|
|
if ($self->{is_comment}) { |
715
|
0
|
|
|
|
|
|
my $tval = $self->{comment}; |
716
|
0
|
|
|
|
|
|
$tval =~ s{&}'&'xmsg; |
717
|
0
|
|
|
|
|
|
$tval =~ s{<}'<'xmsg; |
718
|
0
|
|
|
|
|
|
$tval =~ s{>}'>'xmsg; |
719
|
0
|
|
|
|
|
|
$element .= ""; |
720
|
|
|
|
|
|
|
} |
721
|
0
|
0
|
|
|
|
|
if ($self->{is_end}) { |
722
|
0
|
|
|
|
|
|
$element .= ''.$self->{tag}.'>'; |
723
|
|
|
|
|
|
|
} |
724
|
|
|
|
|
|
|
|
725
|
0
|
|
|
|
|
|
$self->{bush}[$r] .= $element; |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
|
728
|
0
|
0
|
0
|
|
|
|
if ($border and $self->{is_end}) { |
729
|
0
|
|
|
|
|
|
push @{$self->{rresult}}, [$r, $self->{bush}[$r]]; |
|
0
|
|
|
|
|
|
|
730
|
0
|
|
|
|
|
|
$param->{qrfix} = undef; |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
} |
733
|
0
|
|
|
|
|
|
redo; |
734
|
|
|
|
|
|
|
} |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
# Here we check for the {using => ...} option |
737
|
0
|
|
|
|
|
|
$self->{prefix} = ''; |
738
|
|
|
|
|
|
|
|
739
|
0
|
|
|
|
|
|
for my $check (@{$self->{using}}) { |
|
0
|
|
|
|
|
|
|
740
|
0
|
0
|
|
|
|
|
if ($check eq $self->{path}) { |
741
|
0
|
|
|
|
|
|
$self->{prefix} = $check; |
742
|
0
|
|
|
|
|
|
$self->{path} = '/'; |
743
|
0
|
|
|
|
|
|
$self->{level} = 0; |
744
|
0
|
|
|
|
|
|
$self->{tag} = ''; # unfortunately we have to nullify the tag here... |
745
|
0
|
|
|
|
|
|
last; |
746
|
|
|
|
|
|
|
} |
747
|
0
|
0
|
|
|
|
|
if ($check.'/' eq substr($self->{path}, 0, length($check) + 1)) { my @temp = split m{/}xms, $check; |
|
0
|
|
|
|
|
|
|
748
|
0
|
|
|
|
|
|
$self->{prefix} = $check; |
749
|
0
|
|
|
|
|
|
$self->{path} = substr($self->{path}, length($check)); |
750
|
0
|
|
|
|
|
|
$self->{level} -= @temp - 1; |
751
|
0
|
|
|
|
|
|
last; |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
# check if option {using => ...} has been requested, and if so, then skip all |
756
|
|
|
|
|
|
|
# lines that don't have a prefix... |
757
|
0
|
0
|
0
|
|
|
|
if (@{$self->{using}} and $self->{prefix} eq '') { |
|
0
|
|
|
|
|
|
|
758
|
0
|
|
|
|
|
|
redo; |
759
|
|
|
|
|
|
|
} |
760
|
|
|
|
|
|
|
} |
761
|
|
|
|
|
|
|
|
762
|
0
|
|
|
|
|
|
return 1; |
763
|
|
|
|
|
|
|
} |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
sub get_token { |
766
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
767
|
|
|
|
|
|
|
|
768
|
0
|
|
|
|
|
|
until (@{$self->NB_data}) { |
|
0
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
# Here is the all important reading of a chunk of XML-data from the filehandle... |
770
|
|
|
|
|
|
|
|
771
|
0
|
|
|
|
|
|
my $buf; |
772
|
|
|
|
|
|
|
|
773
|
0
|
0
|
|
|
|
|
if (ref($self->NB_fh) eq 'Acme::HTTP') { |
774
|
0
|
|
|
|
|
|
my $ct = $self->NB_fh->read_entity_body($buf, 4096); # returns number of bytes read, or undef if IO-Error |
775
|
0
|
0
|
|
|
|
|
last unless $ct; |
776
|
|
|
|
|
|
|
} |
777
|
|
|
|
|
|
|
else { |
778
|
0
|
|
|
|
|
|
read($self->NB_fh, $buf, 4096); |
779
|
|
|
|
|
|
|
} |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
# We leave immediately as soon as there is no more data left (EOF) |
782
|
0
|
0
|
|
|
|
|
last if $buf eq ''; |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
# and here is the all important parsing of that chunk: |
785
|
|
|
|
|
|
|
# and we could get exceptions thrown here if the XML is invalid... |
786
|
|
|
|
|
|
|
|
787
|
0
|
|
|
|
|
|
$self->{ExpatNB}->parse_more($buf); |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
# ...the recommended way to catch those exceptions is not here, but by wrapping |
790
|
|
|
|
|
|
|
# eval{} around $rdr->iterate like follows |
791
|
|
|
|
|
|
|
# |
792
|
|
|
|
|
|
|
# while (eval{$rdr->iterate}) { |
793
|
|
|
|
|
|
|
# my $text = $rdr->value; |
794
|
|
|
|
|
|
|
# # ... |
795
|
|
|
|
|
|
|
# } |
796
|
|
|
|
|
|
|
# if ($@) { |
797
|
|
|
|
|
|
|
# print "found an error: $@\n"; |
798
|
|
|
|
|
|
|
# } |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
# return failure if end-of-file... |
802
|
0
|
0
|
|
|
|
|
unless (@{$self->NB_data}) { |
|
0
|
|
|
|
|
|
|
803
|
0
|
|
|
|
|
|
return; |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
|
806
|
0
|
|
|
|
|
|
my $token = shift @{$self->NB_data}; |
|
0
|
|
|
|
|
|
|
807
|
0
|
|
|
|
|
|
bless $token, 'XML::Reader::Token'; |
808
|
|
|
|
|
|
|
} |
809
|
|
|
|
|
|
|
sub handle_decl { |
810
|
0
|
|
|
0
|
0
|
|
my ($ExpatNB, $ver, $encoding, $standalone) = @_; |
811
|
|
|
|
|
|
|
|
812
|
0
|
0
|
|
|
|
|
return unless $ExpatNB->{XR_ParseInst}; |
813
|
|
|
|
|
|
|
|
814
|
0
|
|
|
|
|
|
convert_structure($ExpatNB, 'D'); |
815
|
0
|
0
|
|
|
|
|
$ExpatNB->{XR_Decl} = [(defined $ver ? (version => $ver) : ()), |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
816
|
|
|
|
|
|
|
(defined $encoding ? (encoding => $encoding) : ()), |
817
|
|
|
|
|
|
|
(defined $standalone ? (standalone => ($standalone ? 'yes' : 'no')) : ()), |
818
|
|
|
|
|
|
|
]; |
819
|
|
|
|
|
|
|
} |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
sub handle_procinst { |
822
|
0
|
|
|
0
|
0
|
|
my ($ExpatNB, $target, $data) = @_; |
823
|
|
|
|
|
|
|
|
824
|
0
|
0
|
|
|
|
|
return unless $ExpatNB->{XR_ParseInst}; |
825
|
|
|
|
|
|
|
|
826
|
0
|
|
|
|
|
|
convert_structure($ExpatNB, 'P'); |
827
|
0
|
|
|
|
|
|
$ExpatNB->{XR_ProcInst} = [$target, $data]; |
828
|
|
|
|
|
|
|
} |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
sub handle_comment { |
831
|
0
|
|
|
0
|
0
|
|
my ($ExpatNB, $comment) = @_; |
832
|
|
|
|
|
|
|
|
833
|
0
|
0
|
|
|
|
|
return unless $ExpatNB->{XR_ParseComm}; |
834
|
|
|
|
|
|
|
|
835
|
0
|
|
|
|
|
|
convert_structure($ExpatNB, 'C'); |
836
|
0
|
|
|
|
|
|
$ExpatNB->{XR_Comment} = $comment; |
837
|
|
|
|
|
|
|
} |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
sub handle_start { |
840
|
0
|
|
|
0
|
0
|
|
my ($ExpatNB, $element, @attr) = @_; |
841
|
|
|
|
|
|
|
|
842
|
0
|
|
|
|
|
|
convert_structure($ExpatNB, 'S'); |
843
|
0
|
|
|
|
|
|
$ExpatNB->{XR_Att} = \@attr; |
844
|
0
|
|
|
|
|
|
push @{$ExpatNB->{XR_Data}}, ['<', $element]; |
|
0
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
} |
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
sub handle_end { |
848
|
0
|
|
|
0
|
0
|
|
my ($ExpatNB, $element) = @_; |
849
|
|
|
|
|
|
|
|
850
|
0
|
|
|
|
|
|
convert_structure($ExpatNB, 'E'); |
851
|
0
|
|
|
|
|
|
push @{$ExpatNB->{XR_Data}}, ['>', $element]; |
|
0
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
sub handle_char { |
855
|
0
|
|
|
0
|
0
|
|
my ($ExpatNB, $text) = @_; |
856
|
|
|
|
|
|
|
|
857
|
0
|
|
|
|
|
|
$ExpatNB->{XR_Text} .= $text; |
858
|
|
|
|
|
|
|
} |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
sub convert_structure { |
861
|
0
|
|
|
0
|
0
|
|
my ($ExpatNB, $Param_SPECD) = @_; # $Param_SPECD can be either 'S', 'P', 'E', 'C' or 'D' (or even '*') |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
# These are the text and comment that may be stripped |
864
|
0
|
|
|
|
|
|
my $text = $ExpatNB->{XR_Text}; |
865
|
0
|
|
|
|
|
|
my $comment = $ExpatNB->{XR_Comment}; |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
# strip spaces if requested... |
868
|
0
|
0
|
|
|
|
|
if ($ExpatNB->{XR_Strip}) { |
869
|
0
|
|
|
|
|
|
for my $item ($text, $comment) { |
870
|
0
|
|
|
|
|
|
$item =~ s{\A \s+}''xms; |
871
|
0
|
|
|
|
|
|
$item =~ s{\s+ \z}''xms; |
872
|
0
|
|
|
|
|
|
$item =~ s{\s+}' 'xmsg; |
873
|
|
|
|
|
|
|
} |
874
|
|
|
|
|
|
|
} |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
# Don't do anything for the first tag... |
877
|
0
|
0
|
|
|
|
|
unless ($ExpatNB->{XR_Prv_SPECD} eq '') { |
878
|
|
|
|
|
|
|
# Here we save the previous 'SPECD' and the current (i.e. next) 'SPECD' into lexicals |
879
|
|
|
|
|
|
|
# so that we can manipulate them |
880
|
0
|
|
|
|
|
|
my $prev_SPECD = $ExpatNB->{XR_Prv_SPECD}; |
881
|
0
|
|
|
|
|
|
my $next_SPECD = $Param_SPECD; |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
# Do we want , , and pi ?> split up into separate lines ? |
884
|
0
|
0
|
|
|
|
|
if ($ExpatNB->{XR_Split_up}) { |
885
|
0
|
0
|
|
|
|
|
if ($prev_SPECD ne 'E') { |
886
|
|
|
|
|
|
|
# emit the opening tag with empty text |
887
|
0
|
|
|
|
|
|
push @{$ExpatNB->{XR_Data}}, |
|
0
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
['T', '', $comment, $prev_SPECD, '*', $ExpatNB->{XR_Att}, $ExpatNB->{XR_ProcInst}, $ExpatNB->{XR_Decl}]; |
889
|
|
|
|
|
|
|
} |
890
|
|
|
|
|
|
|
|
891
|
0
|
0
|
|
|
|
|
if ($ExpatNB->{XR_Emit_attr}) { |
892
|
|
|
|
|
|
|
# Here we emit attributes on their proper lines -- *after* the start-line (see above) ... |
893
|
0
|
|
|
|
|
|
my %at = @{$ExpatNB->{XR_Att}}; |
|
0
|
|
|
|
|
|
|
894
|
0
|
|
|
|
|
|
for my $key (sort keys %at) { |
895
|
0
|
|
|
|
|
|
push @{$ExpatNB->{XR_Data}}, ['A', $key, $at{$key}]; |
|
0
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
} |
897
|
|
|
|
|
|
|
} |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
# emit text (only if it is not empty) |
900
|
0
|
0
|
|
|
|
|
unless ($text eq '') { |
901
|
0
|
|
|
|
|
|
push @{$ExpatNB->{XR_Data}}, |
|
0
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
['T', $text, '', '-', '*', [], [], []]; |
903
|
|
|
|
|
|
|
} |
904
|
|
|
|
|
|
|
|
905
|
0
|
0
|
|
|
|
|
if ($next_SPECD eq 'E') { |
906
|
|
|
|
|
|
|
# emit the closing tag with empty text |
907
|
0
|
|
|
|
|
|
push @{$ExpatNB->{XR_Data}}, |
|
0
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
['T', '', '', '*', $next_SPECD, [], [], []]; |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
} |
911
|
|
|
|
|
|
|
# Here we don't want , , and pi ?> split up into separate lines ! |
912
|
|
|
|
|
|
|
else { |
913
|
|
|
|
|
|
|
# Do we really want to emit attributes on their proper lines ? -- or do we just |
914
|
|
|
|
|
|
|
# want to publish the attributes on element ${$ExpatNB->{XR_Data}}[5] ? |
915
|
0
|
0
|
|
|
|
|
if ($ExpatNB->{XR_Emit_attr}) { |
916
|
|
|
|
|
|
|
|
917
|
0
|
|
|
|
|
|
my %at = @{$ExpatNB->{XR_Att}}; |
|
0
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
# Here we emit attributes on their proper lines -- *before* the start line (see below) ... |
920
|
0
|
|
|
|
|
|
for my $key (sort keys %at) { |
921
|
0
|
|
|
|
|
|
push @{$ExpatNB->{XR_Data}}, ['A', $key, $at{$key}]; |
|
0
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
} |
924
|
|
|
|
|
|
|
|
925
|
|
|
|
|
|
|
# And here we emit the text |
926
|
0
|
|
|
|
|
|
push @{$ExpatNB->{XR_Data}}, |
|
0
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
['T', $text, $comment, $prev_SPECD, $next_SPECD, $ExpatNB->{XR_Att}, $ExpatNB->{XR_ProcInst}, $ExpatNB->{XR_Decl}]; |
928
|
|
|
|
|
|
|
} |
929
|
|
|
|
|
|
|
} |
930
|
|
|
|
|
|
|
|
931
|
|
|
|
|
|
|
# Initialise values: |
932
|
0
|
|
|
|
|
|
$ExpatNB->{XR_Text} = ''; |
933
|
0
|
|
|
|
|
|
$ExpatNB->{XR_Comment} = ''; |
934
|
0
|
|
|
|
|
|
$ExpatNB->{XR_Att} = []; |
935
|
0
|
|
|
|
|
|
$ExpatNB->{XR_ProcInst} = []; |
936
|
0
|
|
|
|
|
|
$ExpatNB->{XR_Decl} = []; |
937
|
|
|
|
|
|
|
|
938
|
0
|
|
|
|
|
|
$ExpatNB->{XR_Prv_SPECD} = $Param_SPECD; |
939
|
|
|
|
|
|
|
} |
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
sub DESTROY { |
942
|
0
|
|
|
0
|
|
|
my $self = shift; |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
# There are circular references inside an XML::Parser::ExpatNB-object |
945
|
|
|
|
|
|
|
# which need to be cleaned up by calling XML::Parser::Expat->release. |
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
# I quote from the documentation of 'XML::Parser::Expat' (-- XML::Parser::Expat |
948
|
|
|
|
|
|
|
# is a super-class of XML::Parser::ExpatNB --) |
949
|
|
|
|
|
|
|
# |
950
|
|
|
|
|
|
|
# >> ------------------------------------------------------------------------ |
951
|
|
|
|
|
|
|
# >> =item release |
952
|
|
|
|
|
|
|
# >> |
953
|
|
|
|
|
|
|
# >> There are data structures used by XML::Parser::Expat that have circular |
954
|
|
|
|
|
|
|
# >> references. This means that these structures will never be garbage |
955
|
|
|
|
|
|
|
# >> collected unless these references are explicitly broken. Calling this |
956
|
|
|
|
|
|
|
# >> method breaks those references (and makes the instance unusable.) |
957
|
|
|
|
|
|
|
# >> |
958
|
|
|
|
|
|
|
# >> Normally, higher level calls handle this for you, but if you are using |
959
|
|
|
|
|
|
|
# >> XML::Parser::Expat directly, then it's your responsibility to call it. |
960
|
|
|
|
|
|
|
# >> ------------------------------------------------------------------------ |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
# There is a possibility that the XML::Parser::ExpatNB-object did not get |
963
|
|
|
|
|
|
|
# created, while still blessing the XML::Reader object. Therefore we have to |
964
|
|
|
|
|
|
|
# test for this case before calling XML::Parser::ExpatNB->release. |
965
|
|
|
|
|
|
|
|
966
|
0
|
0
|
|
|
|
|
if ($self->{ExpatNB}) { |
967
|
0
|
|
|
|
|
|
$self->{ExpatNB}->release; # ...and not $self->{ExpatNB}->parse_done; |
968
|
|
|
|
|
|
|
} |
969
|
|
|
|
|
|
|
} |
970
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
sub slurp_xml { |
972
|
0
|
|
|
0
|
1
|
|
my $data = shift; |
973
|
|
|
|
|
|
|
|
974
|
0
|
|
|
|
|
|
my @roots; |
975
|
0
|
|
|
|
|
|
my $filter = { filter => 5 }; |
976
|
|
|
|
|
|
|
|
977
|
0
|
|
|
|
|
|
for my $r (@_) { |
978
|
0
|
0
|
|
|
|
|
if (defined $r->{dupatt}) { |
979
|
0
|
|
|
|
|
|
$filter->{dupatt} = $r->{dupatt}; |
980
|
|
|
|
|
|
|
} |
981
|
|
|
|
|
|
|
else { |
982
|
0
|
|
|
|
|
|
push @roots, $r; |
983
|
|
|
|
|
|
|
} |
984
|
|
|
|
|
|
|
} |
985
|
|
|
|
|
|
|
|
986
|
0
|
|
|
|
|
|
my @tree = map {[]} @roots; # start with as many empty lists as there are roots |
|
0
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
|
988
|
0
|
|
|
|
|
|
my $rdr = XML::Reader->new($data, $filter, @roots); |
989
|
|
|
|
|
|
|
|
990
|
0
|
|
|
|
|
|
while ($rdr->iterate) { |
991
|
0
|
|
|
|
|
|
push @{$tree[$rdr->rx]}, $rdr->rvalue; |
|
0
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
} |
993
|
|
|
|
|
|
|
|
994
|
0
|
|
|
|
|
|
return \@tree; |
995
|
|
|
|
|
|
|
} |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
# The package used here - XML::Reader::Token |
998
|
|
|
|
|
|
|
# has been inspired by XML::TokeParser::Token |
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
package XML::Reader::Token; |
1001
|
|
|
|
|
|
|
$XML::Reader::Token::VERSION = '0.65'; |
1002
|
0
|
|
|
0
|
|
|
sub found_start_tag { $_[0][0] eq '<'; } |
1003
|
0
|
|
|
0
|
|
|
sub found_end_tag { $_[0][0] eq '>'; } |
1004
|
0
|
|
|
0
|
|
|
sub found_attr { $_[0][0] eq 'A'; } |
1005
|
0
|
|
|
0
|
|
|
sub found_text { $_[0][0] eq 'T'; } |
1006
|
|
|
|
|
|
|
|
1007
|
0
|
|
|
0
|
|
|
sub extract_tag { $_[0][1]; } # type eq '<' or '>' |
1008
|
|
|
|
|
|
|
|
1009
|
0
|
|
|
0
|
|
|
sub extract_attkey { $_[0][1]; } # type eq 'A' |
1010
|
0
|
|
|
0
|
|
|
sub extract_attval { $_[0][2]; } # type eq 'A' |
1011
|
|
|
|
|
|
|
|
1012
|
0
|
|
|
0
|
|
|
sub extract_text { $_[0][1]; } # type eq 'T' |
1013
|
0
|
|
|
0
|
|
|
sub extract_comment { $_[0][2]; } # type eq 'T' |
1014
|
|
|
|
|
|
|
|
1015
|
0
|
|
|
0
|
|
|
sub extract_prv_SPECD { $_[0][3]; } # type eq 'T' |
1016
|
0
|
|
|
0
|
|
|
sub extract_nxt_SPECD { $_[0][4]; } # type eq 'T' |
1017
|
0
|
|
|
0
|
|
|
sub extract_attr { $_[0][5]; } # type eq 'T' |
1018
|
0
|
|
|
0
|
|
|
sub extract_proc { $_[0][6]; } # type eq 'T' |
1019
|
0
|
|
|
0
|
|
|
sub extract_decl { $_[0][7]; } # type eq 'T' |
1020
|
|
|
|
|
|
|
|
1021
|
|
|
|
|
|
|
1; |
1022
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
__END__ |