line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package XML::Struct; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
845919
|
use strict; |
|
5
|
|
|
|
|
25
|
|
|
5
|
|
|
|
|
168
|
|
4
|
5
|
|
|
5
|
|
2398
|
use XML::LibXML::Reader; |
|
5
|
|
|
|
|
231840
|
|
|
5
|
|
|
|
|
509
|
|
5
|
5
|
|
|
5
|
|
2346
|
use XML::Struct::Reader; |
|
5
|
|
|
|
|
19
|
|
|
5
|
|
|
|
|
226
|
|
6
|
5
|
|
|
5
|
|
2423
|
use XML::Struct::Writer; |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
158
|
|
7
|
5
|
|
|
5
|
|
2190
|
use XML::Struct::Simple; |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
2070
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '0.27'; |
10
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
11
|
|
|
|
|
|
|
our @EXPORT_OK = qw(readXML writeXML simpleXML removeXMLAttr textValues); |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub readXML { # ( [$from], %options ) |
14
|
32
|
50
|
|
32
|
1
|
23767
|
my (%options) = @_ % 2 ? (from => @_) : @_; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
my %reader_options = ( |
17
|
54
|
|
|
|
|
140
|
map { $_ => delete $options{$_} } |
18
|
32
|
|
|
|
|
88
|
grep { exists $options{$_} } |
|
352
|
|
|
|
|
643
|
|
19
|
|
|
|
|
|
|
qw(attributes whitespace path stream simple micro root ns depth content deep) |
20
|
|
|
|
|
|
|
); |
21
|
32
|
50
|
|
|
|
82
|
if (%options) { |
22
|
32
|
50
|
33
|
|
|
163
|
if (exists $options{from} and keys %options == 1) { |
23
|
32
|
|
|
|
|
69
|
$reader_options{from} = $options{from}; |
24
|
|
|
|
|
|
|
} else { |
25
|
0
|
|
|
|
|
0
|
$reader_options{from} = \%options; |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
32
|
|
|
|
|
820
|
XML::Struct::Reader->new( %reader_options )->readDocument; |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub writeXML { |
33
|
1
|
|
|
1
|
1
|
1722
|
my ($xml, %options) = @_; |
34
|
1
|
|
|
|
|
9
|
XML::Struct::Writer->new(%options)->write($xml); |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub simpleXML { |
38
|
1
|
|
|
1
|
1
|
786
|
my ($element, %options) = @_; |
39
|
1
|
|
|
|
|
10
|
XML::Struct::Simple->new(%options)->transform($element); |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
*removeXMLAttr = *XML::Struct::Simple::removeXMLAttr; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# TODO: document (better name?) |
45
|
|
|
|
|
|
|
sub textValues { |
46
|
0
|
|
|
0
|
0
|
|
my ($element, $options) = @_; |
47
|
|
|
|
|
|
|
# TODO: %options (e.g. join => " ") |
48
|
|
|
|
|
|
|
|
49
|
0
|
|
|
|
|
|
my $children = $element->[2]; |
50
|
0
|
0
|
|
|
|
|
return "" if !$children; |
51
|
|
|
|
|
|
|
|
52
|
0
|
|
|
|
|
|
return join "", grep { $_ ne "" } map { |
53
|
0
|
0
|
|
|
|
|
ref $_ ? textValues($_, $options) : $_ |
|
0
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
} @$children; |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
1; |
58
|
|
|
|
|
|
|
__END__ |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=encoding utf8 |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head1 NAME |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
XML-Struct - Represent XML as data structure preserving element order |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=begin markdown |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# Status |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
[](https://travis-ci.org/nichtich/XML-Struct) |
71
|
|
|
|
|
|
|
[](https://coveralls.io/r/nichtich/XML-Struct) |
72
|
|
|
|
|
|
|
[](http://cpants.cpanauthors.org/dist/XML-Struct) |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=end markdown |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head1 SYNOPSIS |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
use XML::Struct qw(readXML writeXML simpleXML); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
my $xml = readXML( "input.xml" ); |
81
|
|
|
|
|
|
|
# [ root => { xmlns => 'http://example.org/' }, [ '!', [ x => {}, [42] ] ] ] |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
my $doc = writeXML( $xml ); |
84
|
|
|
|
|
|
|
# <?xml version="1.0" encoding="UTF-8"?> |
85
|
|
|
|
|
|
|
# <root xmlns="http://example.org/">!<x>42</x></root> |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
my $simple = simpleXML( $xml, root => 'record' ); |
88
|
|
|
|
|
|
|
# { record => { xmlns => 'http://example.org/', x => 42 } } |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=head1 DESCRIPTION |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
L<XML::Struct> implements a mapping between XML and Perl data structures. By |
93
|
|
|
|
|
|
|
default, the mapping preserves element order, so it also suits for |
94
|
|
|
|
|
|
|
"document-oriented" XML. In short, an XML element is represented as array |
95
|
|
|
|
|
|
|
reference with three parts: |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
[ $name => \%attributes, \@children ] |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
This data structure corresponds to the abstract data model of |
100
|
|
|
|
|
|
|
L<MicroXML|http://www.w3.org/community/microxml/>, a simplified subset of XML. |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
If your XML documents don't contain relevant attributes, you can also choose |
103
|
|
|
|
|
|
|
to map to this format: |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
[ $name => \@children ] # element without attributes |
106
|
|
|
|
|
|
|
[ $name ] # empty tag without attributes |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
Both parsing (with L<XML::Struct::Reader> or function C<readXML>) and |
109
|
|
|
|
|
|
|
serializing (with L<XML::Struct::Writer> or function C<writeXML>) are fully |
110
|
|
|
|
|
|
|
based on L<XML::LibXML>, so performance is better than L<XML::Simple> and |
111
|
|
|
|
|
|
|
similar to L<XML::LibXML::Simple>. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=head1 MODULES |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=over |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=item L<XML::Struct::Reader> |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Parse XML as stream into XML data structures. |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=item L<XML::Struct::Writer> |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
Write XML data structures to XML streams for serializing, SAX processing, or |
124
|
|
|
|
|
|
|
creating a DOM object. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=item L<XML::Struct::Writer::Stream> |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
Simplified SAX handler for XML serialization. |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=item L<XML::Struct::Simple> |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
Transform XML data structure into simple form. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=back |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head1 FUNCTIONS |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
The following functions are exported on request: |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=head2 readXML( $source [, %options ] ) |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
Read an XML document with L<XML::Struct::Reader>. The type of source (string, |
143
|
|
|
|
|
|
|
filename, URL, IO Handle...) is detected automatically. See |
144
|
|
|
|
|
|
|
L<XML::Struct::Reader> for options. Options not known to XML::Struct::Reader |
145
|
|
|
|
|
|
|
are passed to L<XML::LibXML::Reader>. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head2 writeXML( $xml [, %options ] ) |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Write an XML document/element with L<XML::Struct::Writer>. See |
150
|
|
|
|
|
|
|
L<XML::Struct::Writer> for options. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head2 simpleXML( $element [, %options ] ) |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Transform an XML document/element into simple key-value format as known from |
155
|
|
|
|
|
|
|
L<XML::Simple>. See L<XML::Struct::Simple> for options. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=head2 removeXMLAttr( $element ) |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Transform XML structure with attributes to XML structure without attributes. |
160
|
|
|
|
|
|
|
The function does not modify the passed element but creates a modified copy. |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
I<this function is deprecated and will be removed in a future release!> |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=head1 EXAMPLE |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
To give an example, with L<XML::Struct::Reader>, this XML document: |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
<root> |
169
|
|
|
|
|
|
|
<foo>text</foo> |
170
|
|
|
|
|
|
|
<bar key="value"> |
171
|
|
|
|
|
|
|
text |
172
|
|
|
|
|
|
|
<doz/> |
173
|
|
|
|
|
|
|
</bar> |
174
|
|
|
|
|
|
|
</root> |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
is transformed to this structure: |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
[ |
179
|
|
|
|
|
|
|
"root", { }, [ |
180
|
|
|
|
|
|
|
[ "foo", { }, "text" ], |
181
|
|
|
|
|
|
|
[ "bar", { key => "value" }, [ |
182
|
|
|
|
|
|
|
"text", |
183
|
|
|
|
|
|
|
[ "doz", { }, [ ] ] |
184
|
|
|
|
|
|
|
] |
185
|
|
|
|
|
|
|
] |
186
|
|
|
|
|
|
|
] |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
This module also supports a simple key-value (aka "data-oriented") format, as |
189
|
|
|
|
|
|
|
used by L<XML::Simple>. With option C<simple> (or function C<simpleXML>) the |
190
|
|
|
|
|
|
|
document given above would be transformed to this structure: |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
{ |
193
|
|
|
|
|
|
|
foo => "text", |
194
|
|
|
|
|
|
|
bar => { |
195
|
|
|
|
|
|
|
key => "value", |
196
|
|
|
|
|
|
|
doz => {} |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head1 SEE ALSO |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
This module was first created to be used in L<Catmandu::XML> and turned out to |
203
|
|
|
|
|
|
|
also become a replacement for L<XML::Simple>. See the former for more XML |
204
|
|
|
|
|
|
|
processing. |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
L<XML::Twig> is another popular and powerfull module for stream-based |
207
|
|
|
|
|
|
|
processing of XML documents. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
See L<XML::Smart>, L<XML::Hash::LX>, L<XML::Parser::Style::ETree>, |
210
|
|
|
|
|
|
|
L<XML::Fast>, and L<XML::Structured> for different representations of XML data |
211
|
|
|
|
|
|
|
as data structures (feel free to implement converters from/to XML::Struct). |
212
|
|
|
|
|
|
|
L<XML::GenericJSON> seems to be an outdated and incomplete attempt to capture |
213
|
|
|
|
|
|
|
more parts of XML Infoset in another data structure. |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
See JSONx for a kind of reverse direction (JSON in XML). |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
This software is copyright (c) 2014 by Jakob VoÃ. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=cut |