line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#! /usr/bin/perl |
2
|
|
|
|
|
|
|
package XML::Tag; |
3
|
4
|
|
|
4
|
|
124239
|
use strict; |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
187
|
|
4
|
4
|
|
|
4
|
|
23
|
use warnings; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
268
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.4'; |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
# ABSTRACT: lib to build builders for xml content |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
sub import { |
10
|
4
|
|
|
4
|
|
29
|
shift; |
11
|
4
|
|
|
|
|
14
|
my ( $caller ) = caller; |
12
|
4
|
|
|
4
|
|
20
|
no strict 'refs'; |
|
4
|
|
|
|
|
18
|
|
|
4
|
|
|
|
|
1885
|
|
13
|
4
|
|
|
|
|
8
|
my @tags = do { |
14
|
4
|
50
|
|
|
|
18
|
if (@_) {@_} |
|
0
|
|
|
|
|
0
|
|
15
|
4
|
|
|
|
|
11
|
else { qw< tag ns as_xml > } |
16
|
|
|
|
|
|
|
}; |
17
|
4
|
|
|
|
|
10
|
for (@tags) { *{"$caller\::$_"} = \&{$_} } |
|
12
|
|
|
|
|
13
|
|
|
12
|
|
|
|
|
1850
|
|
|
12
|
|
|
|
|
25
|
|
18
|
|
|
|
|
|
|
} |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub tag { |
21
|
7
|
|
|
7
|
1
|
853
|
my ( $tag, $code, $attrs ) = @_; |
22
|
7
|
50
|
|
|
|
22
|
my %attr = $attrs ? %$attrs : (); |
23
|
7
|
50
|
|
|
|
19
|
my @data = $code ? $code->() : (); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# TODO: what if blessed ? |
26
|
7
|
|
|
|
|
31
|
while (my $ref = ref $data[0] ) { |
27
|
0
|
0
|
|
|
|
0
|
$ref eq 'HASH' or die "$ref cant hold xml attributes"; |
28
|
0
|
|
|
|
|
0
|
my $news = shift @data; |
29
|
0
|
|
|
|
|
0
|
while ( my ( $k, $v ) = each %$news ) { push @{ $attr{$k} }, $v; } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
0
|
0
|
|
|
|
0
|
my @content = |
33
|
|
|
|
|
|
|
( '<' |
34
|
|
|
|
|
|
|
, $tag |
35
|
|
|
|
|
|
|
, ( keys %attr |
36
|
|
|
|
|
|
|
? ( map { |
37
|
|
|
|
|
|
|
# yeah: i know that this code can lead to stuttering xml like |
38
|
|
|
|
|
|
|
# class="foo foo foo bar" |
39
|
|
|
|
|
|
|
# frankly ? i don't care :-) |
40
|
7
|
50
|
|
|
|
31
|
' ' |
|
|
100
|
|
|
|
|
|
41
|
|
|
|
|
|
|
, $_ |
42
|
|
|
|
|
|
|
, '=' |
43
|
0
|
|
|
|
|
0
|
, ( map {ref $_ ? qq{"@$_"} : qq("$_") } $attr{$_} ) |
44
|
|
|
|
|
|
|
} keys %attr ) |
45
|
|
|
|
|
|
|
: () |
46
|
|
|
|
|
|
|
) |
47
|
|
|
|
|
|
|
, ( @data |
48
|
|
|
|
|
|
|
? ( '>', @data, '', $tag , '>') |
49
|
|
|
|
|
|
|
: '/>' |
50
|
|
|
|
|
|
|
) |
51
|
|
|
|
|
|
|
); |
52
|
|
|
|
|
|
|
|
53
|
7
|
100
|
|
|
|
14
|
if (wantarray) { @content } |
|
4
|
|
|
|
|
34
|
|
54
|
3
|
|
|
|
|
13
|
else { join '', @content } |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub ns { |
59
|
4
|
|
|
4
|
1
|
20931
|
my ( $ns, $pkg ) = do { |
60
|
4
|
|
|
|
|
7
|
my $first = shift; |
61
|
4
|
100
|
100
|
|
|
7
|
if ( ref $first ) { map {$_||=''} @$first } |
|
3
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
14
|
|
62
|
1
|
|
|
|
|
2
|
else { $first, $first } # xml ns = perl package |
63
|
|
|
|
|
|
|
}; |
64
|
4
|
|
66
|
|
|
23
|
$pkg ||= caller; |
65
|
4
|
100
|
|
|
|
11
|
$ns and $ns.=':'; # add namespace separator |
66
|
|
|
|
|
|
|
|
67
|
4
|
|
100
|
|
|
23
|
$_//='' for $ns, $pkg; |
68
|
|
|
|
|
|
|
|
69
|
4
|
|
|
|
|
7
|
for my $spec ( @_ ) { |
70
|
10
|
|
|
|
|
11
|
my ( $sub, $tag ) = do { |
71
|
10
|
100
|
|
|
|
15
|
if ( ref $spec ) { @$spec } |
|
3
|
|
|
|
|
4
|
|
72
|
7
|
|
|
|
|
12
|
else { $spec, $spec } |
73
|
|
|
|
|
|
|
}; |
74
|
4
|
|
|
4
|
|
26
|
no strict 'refs'; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
1304
|
|
75
|
10
|
|
|
3
|
|
1696
|
*{"${pkg}::$sub"} = sub (&) { tag "$ns$tag", @_ } |
|
3
|
|
|
|
|
24
|
|
76
|
10
|
|
|
|
|
45
|
} |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub as_xml (_); |
80
|
|
|
|
|
|
|
sub as_xml (_) { |
81
|
2
|
|
|
2
|
0
|
12
|
my $entry = shift; |
82
|
2
|
|
|
|
|
2
|
my @render; |
83
|
2
|
|
|
|
|
8
|
while ( my ($tag,$v) = each %$entry ) { |
84
|
3
|
100
|
|
|
|
16
|
push @render |
85
|
|
|
|
|
|
|
, "<$tag>" |
86
|
|
|
|
|
|
|
, ( ref $v ? as_xml $v : $v ) |
87
|
|
|
|
|
|
|
, "$tag>" |
88
|
|
|
|
|
|
|
}; |
89
|
2
|
|
|
|
|
8
|
join '', @render; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
1; |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=head1 XML::Tag, a simple XML builder |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
Builders are a set of helpers to generate the tag content. I see 3 major gains |
97
|
|
|
|
|
|
|
using this strategy over templating systems: |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=over 2 |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=item * |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
keep the power of perl in your hands (don't abuse it and respect at least |
104
|
|
|
|
|
|
|
an MVC separation) |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=item * |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
don't be WYSIWYG. When i write code, i need indentations and line feeds |
109
|
|
|
|
|
|
|
to make things readable. All those extra stuff must disapear in the final |
110
|
|
|
|
|
|
|
result because they are useless and anoying when you manage to control spaces |
111
|
|
|
|
|
|
|
with CSS. |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item * |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
stay confident about the quality of generated code: as long as they |
116
|
|
|
|
|
|
|
compiles, the helpers render bug free xml (WARNING: the quality of all PCDATA, |
117
|
|
|
|
|
|
|
attribute values and schemas is *your* job) |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=back |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
L |
122
|
|
|
|
|
|
|
or see it in action: |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
To render this text on C. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
my personal homepage |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
you can use directly the C function from XML::Tag |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
use XML::Tag; |
131
|
|
|
|
|
|
|
use Modern::Perl; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
print '' |
134
|
|
|
|
|
|
|
, tag html => sub { |
135
|
|
|
|
|
|
|
tag head => sub { |
136
|
|
|
|
|
|
|
tag title => sub { +{lang => 'fr'}, "my personal homepage" } |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
you can use the C function from XML::Tag to generate the helpers |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
use XML::Tag; |
143
|
|
|
|
|
|
|
use Modern::Perl; |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
BEGIN { |
146
|
|
|
|
|
|
|
ns '' # use the default namespace |
147
|
|
|
|
|
|
|
, qw< html head title > |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
print '', html { |
151
|
|
|
|
|
|
|
head { |
152
|
|
|
|
|
|
|
title { +{lang => 'fr'}, "my personal homepage" } |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
you can even use a ready to use set of helpers |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
use XML::Tag::html5; |
159
|
|
|
|
|
|
|
print '', html { |
160
|
|
|
|
|
|
|
head { |
161
|
|
|
|
|
|
|
title { +{lang => 'fr'}, "my personal homepage" } |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head2 XML::Tag functions |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=head3 tag |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head3 ns |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head3 tag $name, $content, $attrs |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
the parameters of tag are |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=over 2 |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=item * |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
$name: the name of the tag |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=item * |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
$content: |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
a sub returning th |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
* content sub |
188
|
|
|
|
|
|
|
* a hashref with the list of default attributes for the tag |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item * |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
$name ??? |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=back |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
perl -MXML::Tag -E ' |
197
|
|
|
|
|
|
|
print "($_)" for tag title => sub { "content" }, +{qw(class test)}; |
198
|
|
|
|
|
|
|
' |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
(<)(title)( )(class)(=)("test")(>)(content)()(title)(>) |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
tag title => sub { "content" }, +{qw(class test)} |
204
|
|
|
|
|
|
|
tag title => sub { +{qw(class test)}, "content" } |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
use XML::Tag; |
207
|
|
|
|
|
|
|
print for tag title => sub { "content" }, +{qw(class test)}; |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
use XML::Tag; |
211
|
|
|
|
|
|
|
print for tag title => sub { "content" }, +{qw(class test)}; |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
use XML::Tag; |
214
|
|
|
|
|
|
|
tag title => sub { "content" }, +{qw(class test)} |
215
|
|
|
|
|
|
|
tag title => sub { +{qw(class test)}, "content" } |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
the content sub returns a list, the first elements of the lists are |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
use Modern::Perl; |
221
|
|
|
|
|
|
|
use XML::Tag; |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub foo (&) { tag foo => @_, {qw< isa foo >} } |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
print foo{ |
226
|
|
|
|
|
|
|
+ {qw< class bar id bang >} |
227
|
|
|
|
|
|
|
, {qw< style text-align:center >} |
228
|
|
|
|
|
|
|
, "this is " |
229
|
|
|
|
|
|
|
, "the content" |
230
|
|
|
|
|
|
|
}; |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=head2 how to build tag list |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
extract_elements () { |
235
|
|
|
|
|
|
|
xmlstarlet sel -T -t -m '//xs:element/@name' -v . -n "$@" |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
schema=http://dublincore.org/schemas/xmls/simpledc20021212.xsd |
239
|
|
|
|
|
|
|
curl -ls "$schema" | extract_elements |
240
|
|
|
|
|
|
|
|