File Coverage

blib/lib/XML/Easy/ProceduralWriter.pm
Criterion Covered Total %
statement 41 44 93.1
branch 10 16 62.5
condition 2 6 33.3
subroutine 10 11 90.9
pod 5 5 100.0
total 68 82 82.9


line stmt bran cond sub pod time code
1             package XML::Easy::ProceduralWriter;
2 2     2   98502 use base qw(Exporter);
  2         5  
  2         281  
3              
4 2     2   11 use strict;
  2         184  
  2         73  
5 2     2   12 use warnings;
  2         8  
  2         122  
6              
7             our @EXPORT;
8             our $VERSION = "1.00";
9              
10 2     2   1485 use XML::Easy qw(xml10_write_document);
  2         7574  
  2         121  
11 2     2   14 use Scalar::Util qw(blessed);
  2         3  
  2         274  
12 2     2   22 use Carp qw(croak);
  2         4  
  2         1383  
13              
14             =head1 NAME
15              
16             XML::Easy::ProceduralWriter - even easier writing of XML
17              
18             =head1 SYNOPSIS
19              
20             use XML::Easy::ProceduralWriter;
21              
22             my $octlets = xml_bytes {
23             element "flintstones", contains {
24             element "family", surname => "flintstone", contains {
25             element "person", hair => "black", contains {
26             text "Fred";
27             };
28             element "person", hair => "blonde", contains {
29             text "Wilma";
30             };
31             element "person", hair => "red", contains {
32             text "Pebbles";
33             };
34             };
35             element "family", surname => "rubble", contains {
36             my %h = ("Barney" => "blonde", "Betty" => "black", "BamBam" => "white");
37             foreach (qw( Barney Betty BamBam )) {
38             element "person" hair => $h{$_}, contains { text $_ };
39             }
40             }
41             };
42             };
43              
44             # outputs
45            
46             FredWilmaPebblesBarneyBettyBamBam
47              
48             =head1 DESCRIPTION
49              
50             A procedural wrapper around XML::Easy to provide an alternative way of writing XML
51              
52             =head2 Tutorial
53              
54             You can use this module to write standard XML. You start by saying you want some xml_bytes:
55              
56             my $octlets = xml_bytes {
57             ...
58             };
59              
60             The C command adds a 'tag' to the output. The simpliest form is:
61              
62             xml_bytes {
63             element "a";
64             };
65              
66             Which outputs
67              
68            
69              
70             Note that xml_bytes taks a block - not a data structure - so you can put anything code
71             you want inside block.
72              
73             xml_bytes {
74             if ($foo) { element "a"; }
75             else { element "b"; }
76             }
77              
78             (This is what we mean by "Procedural Writer")
79              
80             You can also use attributes:
81              
82             xml_bytes {
83             element "a", href => "nojs.html", onclick => "openpopup()";
84             }
85              
86             Which outputs
87              
88            
89              
90             You can use the C keyword to add content to the XML node.
91              
92             element "a", href => "nojs.html", onclick => "openpopup()", contains {
93             # ... content here ...
94             };
95              
96             The content can be other tags, text, and any other valid Perl:
97              
98             element "a" href => "nojs.html", onclick => "openpopup()", contains {
99             text "Click ";
100             element "strong", contains {
101             text "Here ";
102             element "em", contains { text "NOW" };
103             };
104             text " please" if $polite;
105             text " $name" if $name;
106             }
107              
108             Which outputs
109              
110             Click Here NOW please Mark
111              
112             =head2 Functions
113              
114             This module exports several functions into your namespace by default. You
115             can use standard Exporter parameters to control which of these are imported
116             into your namespace
117              
118             =over
119              
120             =item xml_element { ... }
121              
122             Takes a codeblock. The code inside the codeblock should call "element" at
123             least once. The XML::Easy::Element created by that element command is
124             returned.
125              
126             You don't normally want to call this function directly, using either C
127             to create something you can print out or C to create individual xml "tags".
128             The one occasion that it might make sense to use this function is where you want
129             to use an encoding other than UTF-8:
130              
131             use XML::Easy qq(xml10_write_document);
132             print xml10_write_document(xml_element {
133             element "song", title => "Green Bottles", contains {
134             foreach my $bottles (reverse (1..10)) {
135             element "verse", contains {
136             element "line", contains {
137             text "$bottles green bottle";
138             text "s" unless $bottles == 1;
139             text " hanging on the wall";
140             } for (1..2);
141             element "line", contains {
142             text "if 1 green bottle should accidentally fall";
143             };
144             element "line", contains {
145             text "then they'd be ".($bottles > 1 ? $bottles-1 : "no")." green bottle";
146             text "s" unless $bottles-1 == 1;
147             text " hanging on the wall";
148             };
149             };
150             }
151             }, "UTF-16BE");
152              
153             =cut
154              
155             sub xml_element(&) {
156              
157             # create a temporary place to store whatever we're putting
158 1     1 1 17 local @XML::Easy::ProceduralWriter::stuff = ();
159 1         5 shift->();
160              
161 1 50       10 croak "No root node specified"
162             unless @XML::Easy::ProceduralWriter::stuff;
163              
164 1 50       4 croak "More than one root node specified"
165             if @XML::Easy::ProceduralWriter::stuff > 3;
166              
167 1 50       6 croak "Text before root node!"
168             unless $XML::Easy::ProceduralWriter::stuff[0] eq "";
169              
170 1 50 33     5 croak "Text after root node!"
171             if defined($XML::Easy::ProceduralWriter::stuff[2]) && $XML::Easy::ProceduralWriter::stuff[2] ne "";
172              
173 1         2091 return $XML::Easy::ProceduralWriter::stuff[1]
174             }
175             push @EXPORT, "xml_element";
176              
177              
178             =item xml_bytes { ... }
179              
180             The same as xml_element, but returns a scalar containing octlets that have a UTF-8
181             encoded representation of the character representation of the string (i.e. this is
182             what you want to use to create something you can pass to C)
183              
184             =cut
185              
186             sub xml_bytes(&) {
187 0     0 1 0 my $data = shift;
188 0         0 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
189 0         0 return xml10_write_document(&xml_element($data), "UTF-8"); ## no critic Subroutines::ProhibitAmpersandSigils
190             }
191             push @EXPORT, "xml_bytes";
192              
193             =item element $element_name, $key => $value, $key => $value, $block
194              
195             Create an XML::Easy::Element element and add it to the enclosing element.
196              
197             =cut
198              
199             sub element($;@) {
200 51     51 1 2436 my $tag_name = shift;
201              
202 51         323 my @stuff;
203 51 50 33     1179 if (ref $_[-1] && ref $_[-1] eq "CODE") {
204 51         97 local @XML::Easy::ProceduralWriter::stuff = ();
205 51         116 (pop)->();
206 51         434 @stuff = @XML::Easy::ProceduralWriter::stuff;
207             }
208 51 100       134 push @stuff, "" unless @stuff % 2;
209 51 50       151 push @XML::Easy::ProceduralWriter::stuff, "" unless @XML::Easy::ProceduralWriter::stuff % 2;
210 51         1001 push @XML::Easy::ProceduralWriter::stuff, XML::Easy::Element->new($tag_name, {@_}, \@stuff);
211 51         268 return;
212             }
213             push @EXPORT, "element";
214              
215             =item text $text
216              
217             Create text and add it to the enclosing element.
218              
219             =cut
220              
221             # simply takes it's argument and appends it to @XML::Easy::ProceduralWriter::stuff
222             sub text($) {
223 97     97 1 416 my $text = shift;
224 97 100       947 if (@XML::Easy::ProceduralWriter::stuff % 2)
225 57         105 { $XML::Easy::ProceduralWriter::stuff[-1] .= $text }
226             else
227 40         75 { push @XML::Easy::ProceduralWriter::stuff, $text }
228 97         6377 return;
229             }
230             push @EXPORT, "text";
231              
232             =item contains { ... }
233              
234             Syntatic sugar for "sub { ... }"
235              
236             =cut
237              
238             # syntatic sugar to allows us to write "contains { ... }" rather than "sub { ... }"
239             sub contains (&) {
240 51     51 1 513 return $_[0]
241             }
242             push @EXPORT, "contains";
243              
244             =back
245              
246             =head1 AUTHOR
247              
248             Mark Fowler . Developed by Photoways whist working
249             on the Photobox website.
250              
251             Copyright (C) Photoways Ltd 2008, all rights reserved.
252              
253             If you send me an email about this module, there's a good chance my overly
254             agressive spam filter will never let me see it. Please use http://rt.cpan.org/
255             to report bugs and request new features instead.
256              
257             =head1 LICENSE
258              
259             This module is free software; you can redistribute it and/or modify it
260             under the same terms as Perl itself.
261              
262             =head1 BUGS
263              
264             Chucks a lot of stuff into your namespace.
265              
266             Some people might consider it a bug that this module does not produce
267             a C<< > declaration when we convert to bytes. I consider this
268             a feature.
269              
270             =head1 SEE ALSO
271              
272             L
273              
274             =cut
275              
276             1;