line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package XML::MyXML::Object; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
40
|
use strict; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
153
|
|
4
|
5
|
|
|
5
|
|
24
|
use warnings; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
152
|
|
5
|
|
|
|
|
|
|
|
6
|
5
|
|
|
5
|
|
2085
|
use XML::MyXML::Util 'trim', 'strip_ns'; |
|
5
|
|
|
|
|
27
|
|
|
5
|
|
|
|
|
349
|
|
7
|
|
|
|
|
|
|
|
8
|
5
|
|
|
5
|
|
3927
|
use Encode; |
|
5
|
|
|
|
|
46889
|
|
|
5
|
|
|
|
|
420
|
|
9
|
5
|
|
|
5
|
|
52
|
use Carp; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
363
|
|
10
|
5
|
|
|
5
|
|
36
|
use Scalar::Util 'weaken'; |
|
5
|
|
|
|
|
20
|
|
|
5
|
|
|
|
|
14010
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = "1.08"; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub new { |
15
|
0
|
|
|
0
|
0
|
0
|
my $class = shift; |
16
|
0
|
|
|
|
|
0
|
my $xml = shift; |
17
|
|
|
|
|
|
|
|
18
|
0
|
|
|
|
|
0
|
return bless XML::MyXML::xml_to_object($xml), $class; |
19
|
|
|
|
|
|
|
} |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
my $ch0 = chr(0); |
22
|
|
|
|
|
|
|
sub _string_unescape { |
23
|
50
|
|
|
50
|
|
1591
|
my $string = shift; |
24
|
|
|
|
|
|
|
|
25
|
50
|
100
|
|
|
|
124
|
defined $string or return undef; |
26
|
|
|
|
|
|
|
|
27
|
33
|
|
|
|
|
1993
|
my $ret = eval "qq${ch0}$string${ch0}"; |
28
|
33
|
50
|
|
|
|
134
|
defined $ret or croak "Can't unescape this string: $string"; |
29
|
|
|
|
|
|
|
|
30
|
33
|
|
|
|
|
151
|
return $ret; |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub _parse_description { |
34
|
77
|
|
|
77
|
|
149
|
my ($desc) = @_; |
35
|
|
|
|
|
|
|
|
36
|
77
|
|
|
|
|
508
|
my ($el_name, $el_ns, $attrs_str) = $desc =~ / |
37
|
|
|
|
|
|
|
# start anchor |
38
|
|
|
|
|
|
|
^ |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# element name |
41
|
|
|
|
|
|
|
( |
42
|
|
|
|
|
|
|
(?: |
43
|
|
|
|
|
|
|
\\ \[ |
44
|
|
|
|
|
|
|
| |
45
|
|
|
|
|
|
|
\\ \{ |
46
|
|
|
|
|
|
|
| |
47
|
|
|
|
|
|
|
[^\[\{] |
48
|
|
|
|
|
|
|
)* |
49
|
|
|
|
|
|
|
) |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# element namespace |
52
|
|
|
|
|
|
|
(?: |
53
|
|
|
|
|
|
|
# opening curly bracket |
54
|
|
|
|
|
|
|
\{ |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# namespace name |
57
|
|
|
|
|
|
|
((?: \\ \} | [^\}] )*) |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# closing curly bracket |
60
|
|
|
|
|
|
|
\} |
61
|
|
|
|
|
|
|
)? |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# attributes string |
64
|
|
|
|
|
|
|
(.*) |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# end anchor |
67
|
|
|
|
|
|
|
\z |
68
|
|
|
|
|
|
|
/x; |
69
|
|
|
|
|
|
|
|
70
|
77
|
|
|
|
|
228
|
my @attrs = $attrs_str =~ / |
71
|
|
|
|
|
|
|
# opening square bracket |
72
|
|
|
|
|
|
|
\[ |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# attribute name |
75
|
|
|
|
|
|
|
( |
76
|
|
|
|
|
|
|
# attribute characters |
77
|
|
|
|
|
|
|
(?: \\ \] | \\ \= | \\ \{ | [^\]\=\{] )+ |
78
|
|
|
|
|
|
|
) |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# optional namespace |
81
|
|
|
|
|
|
|
(?: |
82
|
|
|
|
|
|
|
# opening curly bracket |
83
|
|
|
|
|
|
|
\{ |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# namespace name |
86
|
|
|
|
|
|
|
((?: \\ \} | [^\}] )*) |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# closing curly bracket |
89
|
|
|
|
|
|
|
\} |
90
|
|
|
|
|
|
|
)? |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# value option |
93
|
|
|
|
|
|
|
(?: |
94
|
|
|
|
|
|
|
# equals sign |
95
|
|
|
|
|
|
|
\= |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# value |
98
|
|
|
|
|
|
|
( |
99
|
|
|
|
|
|
|
(?: \\ \] | [^\]] )* |
100
|
|
|
|
|
|
|
) |
101
|
|
|
|
|
|
|
)? |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# closing square bracket |
104
|
|
|
|
|
|
|
\] |
105
|
|
|
|
|
|
|
/gx; |
106
|
|
|
|
|
|
|
|
107
|
77
|
|
|
|
|
113
|
my %attrs; |
108
|
77
|
|
|
|
|
189
|
while (@attrs) { |
109
|
15
|
|
|
|
|
45
|
my ($attr_name, $attr_ns, $attr_value) = splice @attrs, 0, 3; |
110
|
|
|
|
|
|
|
# $attr_value =~ s/^\"|\"\z//g if defined $attr_value; |
111
|
15
|
|
|
|
|
41
|
$attrs{_string_unescape $attr_name} = { |
112
|
|
|
|
|
|
|
ns => _string_unescape($attr_ns), |
113
|
|
|
|
|
|
|
value => _string_unescape($attr_value), |
114
|
|
|
|
|
|
|
}; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
77
|
|
|
|
|
258
|
return ($el_name, $el_ns, \%attrs); |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub cmp_element { |
121
|
155
|
|
|
155
|
0
|
277
|
my ($self, $desc) = @_; |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
my ($el_name, $el_ns, $attrs) = ref $desc |
124
|
155
|
100
|
|
|
|
411
|
? @$desc{qw/ el_name el_ns attrs /} |
125
|
|
|
|
|
|
|
: _parse_description($desc); |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# check element name |
128
|
155
|
100
|
|
|
|
289
|
if (length $el_name) { |
129
|
147
|
100
|
|
|
|
255
|
if (! defined $el_ns) { |
|
|
50
|
|
|
|
|
|
130
|
145
|
100
|
|
|
|
417
|
$self->{el_name} eq $el_name or return 0; |
131
|
|
|
|
|
|
|
} elsif (length $el_ns) { |
132
|
2
|
50
|
|
|
|
7
|
$el_name !~ /\:/ or croak 'You can either have a ns requirement, or a ":" in your path segment'; |
133
|
2
|
50
|
|
|
|
11
|
exists $self->{ns_data}{"$el_ns:"} or return 0; |
134
|
2
|
50
|
|
|
|
10
|
strip_ns($self->{el_name}) eq $el_name or return 0; |
135
|
|
|
|
|
|
|
} else { |
136
|
|
|
|
|
|
|
# ! grep /\:\z/, keys %{ $self->{ns_data} } or return 0; |
137
|
|
|
|
|
|
|
# $self->{el_name} eq $el_name or return 0; |
138
|
0
|
|
|
|
|
0
|
croak 'empty ns in path segment'; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# check attributes |
143
|
115
|
|
|
|
|
266
|
foreach my $attr_name (keys %$attrs) { |
144
|
50
|
|
|
|
|
78
|
my ($attr_ns, $attr_value) = @{ $attrs->{$attr_name} }{qw/ ns value /}; |
|
50
|
|
|
|
|
95
|
|
145
|
50
|
100
|
|
|
|
91
|
if (! defined $attr_ns) { |
|
|
50
|
|
|
|
|
|
146
|
48
|
|
|
|
|
87
|
my $actual_attr_value = $self->attr($attr_name); |
147
|
48
|
100
|
|
|
|
131
|
defined $actual_attr_value or return 0; |
148
|
35
|
100
|
100
|
|
|
175
|
! defined $attr_value or $attr_value eq $actual_attr_value or return 0; |
149
|
|
|
|
|
|
|
} elsif (length $attr_ns) { |
150
|
2
|
50
|
|
|
|
10
|
$attr_name !~ /\:/ or croak 'You can either have a ns requirement, or a ":" in your path segment'; |
151
|
2
|
|
|
|
|
7
|
my $actual_attr_value = $self->{ns_data}{"$attr_ns:$attr_name"}; |
152
|
2
|
100
|
|
|
|
12
|
defined $actual_attr_value or return 0; |
153
|
1
|
50
|
33
|
|
|
6
|
! defined $attr_value or $attr_value eq $actual_attr_value or return 0; |
154
|
|
|
|
|
|
|
} else { |
155
|
|
|
|
|
|
|
# my $actual_attr_value = $self->attr($attr_name); |
156
|
|
|
|
|
|
|
# defined $actual_attr_value or return 0; |
157
|
|
|
|
|
|
|
# ! exists $self->{ns_data}{} |
158
|
0
|
|
|
|
|
0
|
croak 'empty ns in path segment'; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
82
|
|
|
|
|
340
|
return 1; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub children { |
166
|
197
|
|
|
197
|
0
|
292
|
my $self = shift; |
167
|
197
|
|
|
|
|
291
|
my $path_segment = shift; |
168
|
|
|
|
|
|
|
|
169
|
197
|
100
|
|
|
|
413
|
$path_segment = '' if ! defined $path_segment; |
170
|
|
|
|
|
|
|
|
171
|
197
|
|
|
|
|
267
|
my @all_children = grep { defined $_->{el_name} } @{$self->{content}}; |
|
299
|
|
|
|
|
597
|
|
|
197
|
|
|
|
|
379
|
|
172
|
197
|
100
|
|
|
|
735
|
length $path_segment or return @all_children; |
173
|
|
|
|
|
|
|
|
174
|
65
|
|
|
|
|
136
|
my ($el_name, $el_ns, $attrs) = _parse_description($path_segment); |
175
|
65
|
|
|
|
|
220
|
my $desc = { el_name => $el_name, el_ns => $el_ns, attrs => $attrs }; |
176
|
|
|
|
|
|
|
|
177
|
65
|
|
|
|
|
186
|
return grep $_->cmp_element($desc), @all_children; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub path { |
181
|
41
|
|
|
41
|
0
|
8909
|
my $self = shift; |
182
|
41
|
|
|
|
|
86
|
my $path = shift; |
183
|
|
|
|
|
|
|
|
184
|
41
|
|
|
|
|
76
|
my $original_path = $path; |
185
|
41
|
|
|
|
|
129
|
my $path_starts_with_root = $path =~ m|^/|; |
186
|
41
|
100
|
|
|
|
149
|
$path = "/$path" unless $path_starts_with_root; |
187
|
41
|
|
|
|
|
491
|
my @path_segments = $path =~ m! |
188
|
|
|
|
|
|
|
# slash |
189
|
|
|
|
|
|
|
\/ |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
( |
192
|
|
|
|
|
|
|
# allowed strings |
193
|
|
|
|
|
|
|
(?: |
194
|
|
|
|
|
|
|
# escaped "/" |
195
|
|
|
|
|
|
|
\\ \/ |
196
|
|
|
|
|
|
|
| |
197
|
|
|
|
|
|
|
# escaped "[" |
198
|
|
|
|
|
|
|
\\ \[ |
199
|
|
|
|
|
|
|
| |
200
|
|
|
|
|
|
|
# escaped "{" |
201
|
|
|
|
|
|
|
\\ \{ |
202
|
|
|
|
|
|
|
| |
203
|
|
|
|
|
|
|
# non- "/", "[", "]" |
204
|
|
|
|
|
|
|
[^\/\[\{] |
205
|
|
|
|
|
|
|
| |
206
|
|
|
|
|
|
|
# attribute |
207
|
|
|
|
|
|
|
\[ |
208
|
|
|
|
|
|
|
(?: \\ \] | [^\]] )* |
209
|
|
|
|
|
|
|
\] |
210
|
|
|
|
|
|
|
| |
211
|
|
|
|
|
|
|
# namespace |
212
|
|
|
|
|
|
|
\{ |
213
|
|
|
|
|
|
|
(?: \\ \} | [^\}] )* |
214
|
|
|
|
|
|
|
\} |
215
|
|
|
|
|
|
|
)* |
216
|
|
|
|
|
|
|
) |
217
|
|
|
|
|
|
|
!gx; |
218
|
|
|
|
|
|
|
|
219
|
41
|
|
|
|
|
92
|
my @result = ($self); |
220
|
41
|
100
|
100
|
|
|
121
|
$self->cmp_element(shift @path_segments) or return if $path_starts_with_root; |
221
|
40
|
|
|
|
|
92
|
foreach my $path_segment (@path_segments) { |
222
|
58
|
50
|
|
|
|
157
|
@result = map $_->children($path_segment), @result or return; |
223
|
|
|
|
|
|
|
} |
224
|
40
|
100
|
|
|
|
269
|
return wantarray ? @result : $result[0]; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
sub text { |
228
|
53
|
|
|
53
|
0
|
87
|
my $self = shift; |
229
|
53
|
100
|
100
|
|
|
186
|
my $flags = (@_ and ref $_[-1]) ? pop : {}; |
230
|
53
|
100
|
|
|
|
150
|
my $set_value = @_ ? (defined $_[0] ? shift : '') : undef; |
|
|
100
|
|
|
|
|
|
231
|
|
|
|
|
|
|
|
232
|
53
|
100
|
|
|
|
120
|
if (! defined $set_value) { |
233
|
50
|
|
|
|
|
79
|
my $value = ''; |
234
|
50
|
100
|
|
|
|
124
|
if ($self->{content}) { |
235
|
28
|
|
|
|
|
38
|
$value .= $_->text($flags) foreach @{ $self->{content} }; |
|
28
|
|
|
|
|
86
|
|
236
|
|
|
|
|
|
|
} |
237
|
50
|
100
|
|
|
|
104
|
if ($self->{text}) { |
238
|
22
|
|
|
|
|
46
|
my $temp_value = $self->{text}; |
239
|
22
|
100
|
|
|
|
53
|
$temp_value = trim $temp_value if $flags->{strip}; |
240
|
22
|
|
|
|
|
49
|
$value .= $temp_value; |
241
|
|
|
|
|
|
|
} |
242
|
50
|
|
|
|
|
201
|
return $value; |
243
|
|
|
|
|
|
|
} else { |
244
|
3
|
100
|
|
|
|
9
|
if (length $set_value) { |
245
|
1
|
|
|
|
|
4
|
my $entry = bless { |
246
|
|
|
|
|
|
|
text => $set_value, |
247
|
|
|
|
|
|
|
parent => $self |
248
|
|
|
|
|
|
|
}, 'XML::MyXML::Object'; |
249
|
1
|
|
|
|
|
5
|
weaken $entry->{parent}; |
250
|
1
|
|
|
|
|
7
|
$self->{content} = [ $entry ]; |
251
|
|
|
|
|
|
|
} else { |
252
|
2
|
|
|
|
|
9
|
$self->{content} = []; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
*value = \&text; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub inner_xml { |
260
|
7
|
|
|
7
|
0
|
2280
|
my $self = shift; |
261
|
7
|
100
|
100
|
|
|
40
|
my $flags = (@_ and ref $_[-1]) ? pop : {}; |
262
|
7
|
100
|
|
|
|
26
|
my $set_xml = @_ ? defined $_[0] ? shift : '' : undef; |
|
|
100
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
264
|
7
|
100
|
|
|
|
18
|
if (! defined $set_xml) { |
265
|
3
|
|
|
|
|
11
|
my $xml = $self->to_xml($flags); |
266
|
3
|
|
|
|
|
20
|
$xml =~ s/^\<.*?\>//s; |
267
|
3
|
|
|
|
|
15
|
$xml =~ s/\<\/[^\>]*\>\z//s; # nothing to remove if empty element |
268
|
3
|
|
|
|
|
17
|
return $xml; |
269
|
|
|
|
|
|
|
} else { |
270
|
4
|
|
|
|
|
13
|
my $xml = " $set_xml "; |
271
|
4
|
|
|
|
|
31
|
my $obj = XML::MyXML::xml_to_object($xml, $flags); |
272
|
4
|
|
|
|
|
24
|
$self->{content} = []; |
273
|
4
|
100
|
|
|
|
10
|
foreach my $child (@{ $obj->{content} || [] }) { |
|
4
|
|
|
|
|
25
|
|
274
|
5
|
|
|
|
|
9
|
$child->{parent} = $self; |
275
|
5
|
|
|
|
|
17
|
weaken $child->{parent}; |
276
|
5
|
|
|
|
|
7
|
push @{ $self->{content} }, $child; |
|
5
|
|
|
|
|
9
|
|
277
|
5
|
100
|
|
|
|
19
|
$child->_apply_namespace_declarations if $child->{el_name}; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub attr { |
283
|
199
|
|
|
199
|
0
|
288
|
my $self = shift; |
284
|
199
|
|
|
|
|
278
|
my $attr_name = shift; |
285
|
199
|
50
|
|
|
|
408
|
my $flags = ref $_[-1] ? pop : {}; |
286
|
199
|
|
|
|
|
333
|
my ($set_to, $must_set); |
287
|
199
|
100
|
|
|
|
434
|
if (@_) { |
288
|
4
|
|
|
|
|
10
|
$set_to = shift; |
289
|
4
|
|
|
|
|
7
|
$must_set = 1; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
199
|
100
|
|
|
|
389
|
if (defined $attr_name) { |
293
|
67
|
100
|
|
|
|
117
|
if ($must_set) { |
294
|
4
|
100
|
|
|
|
12
|
if (defined ($set_to)) { |
295
|
3
|
|
|
|
|
9
|
$self->{attrs}{$attr_name} = $set_to; |
296
|
|
|
|
|
|
|
} else { |
297
|
1
|
|
|
|
|
4
|
delete $self->{attrs}{$attr_name}; |
298
|
|
|
|
|
|
|
} |
299
|
4
|
100
|
|
|
|
22
|
if ($attr_name =~ /^xmlns(\:|\z)/) { |
300
|
2
|
|
|
|
|
5
|
$self->_apply_namespace_declarations; |
301
|
|
|
|
|
|
|
} |
302
|
4
|
|
|
|
|
13
|
return $set_to; |
303
|
|
|
|
|
|
|
} else { |
304
|
63
|
|
|
|
|
227
|
return $self->{attrs}->{$attr_name}; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
} else { |
307
|
132
|
|
|
|
|
169
|
return %{$self->{attrs}}; |
|
132
|
|
|
|
|
568
|
|
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub tag { |
312
|
5
|
|
|
5
|
0
|
17
|
my $self = shift; |
313
|
5
|
|
100
|
|
|
24
|
my $flags = shift || {}; |
314
|
|
|
|
|
|
|
|
315
|
5
|
|
|
|
|
10
|
my $el_name = $self->{el_name}; |
316
|
5
|
50
|
|
|
|
13
|
if (defined $el_name) { |
317
|
5
|
100
|
|
|
|
23
|
$el_name =~ s/^.*\:// if $flags->{strip_ns}; |
318
|
5
|
|
|
|
|
29
|
return $el_name; |
319
|
|
|
|
|
|
|
} else { |
320
|
0
|
|
|
|
|
0
|
return undef; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
*name = \&tag; |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
sub parent { |
327
|
2
|
|
|
2
|
0
|
6
|
my $self = shift; |
328
|
|
|
|
|
|
|
|
329
|
2
|
|
|
|
|
11
|
return $self->{parent}; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
sub simplify { |
333
|
13
|
|
|
13
|
0
|
27
|
my $self = shift; |
334
|
13
|
|
100
|
|
|
34
|
my $flags = shift || {}; |
335
|
|
|
|
|
|
|
|
336
|
13
|
|
|
|
|
49
|
my $simple = XML::MyXML::_objectarray_to_simple([$self], $flags); |
337
|
|
|
|
|
|
|
|
338
|
13
|
100
|
|
|
|
43
|
if ($flags->{internal}) { |
339
|
5
|
0
|
|
|
|
23
|
$simple = |
|
|
50
|
|
|
|
|
|
340
|
|
|
|
|
|
|
ref $simple eq 'HASH' ? (values %$simple)[0] |
341
|
|
|
|
|
|
|
: ref $simple eq 'ARRAY' ? $simple->[1] |
342
|
|
|
|
|
|
|
: croak; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
13
|
|
|
|
|
72
|
return $simple; |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
sub to_xml { |
349
|
21
|
|
|
21
|
0
|
1526
|
my $self = shift; |
350
|
21
|
|
100
|
|
|
81
|
my $flags = shift || {}; |
351
|
|
|
|
|
|
|
|
352
|
21
|
|
|
|
|
40
|
my $decl = ''; |
353
|
21
|
50
|
|
|
|
54
|
$decl .= qq'\n' if $flags->{complete}; |
354
|
21
|
|
|
|
|
82
|
my $xml = XML::MyXML::_objectarray_to_xml([$self]); |
355
|
|
|
|
|
|
|
$xml = XML::MyXML::tidy_xml($xml, { |
356
|
|
|
|
|
|
|
%$flags, |
357
|
|
|
|
|
|
|
bytes => 0, |
358
|
|
|
|
|
|
|
complete => 0, |
359
|
|
|
|
|
|
|
save => undef |
360
|
21
|
100
|
|
|
|
80
|
}) if $flags->{tidy}; |
361
|
21
|
|
|
|
|
50
|
$xml = $decl . $xml; |
362
|
21
|
50
|
|
|
|
66
|
if (defined $flags->{save}) { |
363
|
0
|
0
|
|
|
|
0
|
open my $fh, '>', $flags->{save} or croak "Error: Couldn't open file '$flags->{save}' for writing: $!"; |
364
|
0
|
|
|
|
|
0
|
binmode $fh, ':encoding(UTF-8)'; |
365
|
0
|
|
|
|
|
0
|
print $fh $xml; |
366
|
0
|
|
|
|
|
0
|
close $fh; |
367
|
|
|
|
|
|
|
} |
368
|
21
|
100
|
|
|
|
65
|
$xml = encode_utf8 $xml if $flags->{bytes}; |
369
|
21
|
|
|
|
|
131
|
return $xml; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub to_tidy_xml { |
373
|
1
|
|
|
1
|
0
|
791
|
my $self = shift; |
374
|
1
|
|
50
|
|
|
6
|
my $flags = shift || {}; |
375
|
|
|
|
|
|
|
|
376
|
1
|
|
|
|
|
6
|
return $self->to_xml({ %$flags, tidy => 1 }); |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
sub _apply_namespace_declarations { |
380
|
132
|
|
|
132
|
|
215
|
my $self = shift; |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# only elements |
383
|
132
|
50
|
|
|
|
322
|
$self->{el_name} or return; |
384
|
|
|
|
|
|
|
|
385
|
132
|
|
|
|
|
303
|
my %attr = $self->attr; |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
# parse namespace declarations |
388
|
132
|
|
|
|
|
290
|
my ($ns_info, @cancel_declarations) = ({}); |
389
|
132
|
|
|
|
|
370
|
foreach my $ns_decl_attr_name (grep /^xmlns(\:|\z)/, keys %attr) { |
390
|
7
|
|
|
|
|
31
|
my ($ns_prefix) = $ns_decl_attr_name =~ /^xmlns(?:\:(.+))?\z/; |
391
|
7
|
100
|
|
|
|
23
|
$ns_prefix = '' if ! defined $ns_prefix; |
392
|
7
|
100
|
|
|
|
22
|
if (length $attr{$ns_decl_attr_name}) { |
393
|
5
|
|
|
|
|
17
|
$ns_info->{$ns_prefix} = $attr{$ns_decl_attr_name}; |
394
|
|
|
|
|
|
|
} else { |
395
|
2
|
|
|
|
|
7
|
push @cancel_declarations, $ns_prefix; |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
# insert these declarations into the full_ns_info hashref |
400
|
|
|
|
|
|
|
$self->{full_ns_info} = (%$ns_info or @cancel_declarations) ? { |
401
|
6
|
|
|
|
|
36
|
%{ $self->{parent}{full_ns_info} }, |
402
|
|
|
|
|
|
|
%$ns_info, |
403
|
132
|
100
|
100
|
|
|
614
|
} : $self->{parent}{full_ns_info}; |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
# remove cancelled declarations (can cancel with ns name = "") |
406
|
132
|
|
|
|
|
247
|
delete @{ $self->{full_ns_info} }{@cancel_declarations}; |
|
132
|
|
|
|
|
264
|
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
# ns_data is... |
409
|
|
|
|
|
|
|
# $ns_name: => undef for element name |
410
|
|
|
|
|
|
|
# $ns_name:$attr_localpart => $attr_value for attributes |
411
|
132
|
|
|
|
|
267
|
$self->{ns_data} = {}; |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
# apply all active declarations to element |
414
|
132
|
|
|
|
|
225
|
my $el_name = $self->{el_name}; |
415
|
132
|
|
|
|
|
340
|
my $num_colons = () = $el_name =~ /(\:)/g; |
416
|
132
|
|
|
|
|
207
|
my $ns_name = do { |
417
|
132
|
100
|
|
|
|
277
|
if ($num_colons == 0) { |
|
|
50
|
|
|
|
|
|
418
|
128
|
|
|
|
|
237
|
$self->{full_ns_info}{''}; |
419
|
|
|
|
|
|
|
} elsif ($num_colons == 1) { |
420
|
4
|
|
|
|
|
31
|
my ($prefix) = $el_name =~ /^(.+)?\:./; # colon must not be at start or end |
421
|
4
|
50
|
|
|
|
20
|
defined $prefix ? $self->{full_ns_info}{$prefix} : undef; |
422
|
|
|
|
|
|
|
} else { |
423
|
0
|
|
|
|
|
0
|
undef; |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
}; |
426
|
132
|
100
|
66
|
|
|
355
|
$self->{ns_data}{"$ns_name:"} = undef if defined $ns_name and length $ns_name; |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# apply all active declarations to attributes |
429
|
132
|
|
|
|
|
302
|
foreach my $attr_name (keys %attr) { |
430
|
58
|
100
|
|
|
|
157
|
if ($attr_name =~ /^([^\:]+)\:([^\:]+)\z/) { # if has one colon, not at the edges |
431
|
7
|
|
|
|
|
25
|
my ($prefix, $localpart) = ($1, $2); |
432
|
7
|
|
|
|
|
15
|
my $ns_name = $self->{full_ns_info}{$prefix}; |
433
|
7
|
100
|
66
|
|
|
43
|
$self->{ns_data}{"$ns_name:$localpart"} = $attr{$attr_name} |
434
|
|
|
|
|
|
|
if defined $ns_name and length $ns_name; |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# continue by applying to all children (and further ancestors) |
439
|
132
|
|
|
|
|
307
|
$_->_apply_namespace_declarations foreach $self->children; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
1; |