File Coverage

lib/XML/Declare.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             # XML::LibXML > 1.90 overloads Element
2 2     2   57310 use XML::LibXML ();
  0            
  0            
3              
4             {
5             package # hide
6             XML::LibXML::Node;
7             use Scalar::Util ();
8             use overload ();
9             BEGIN {
10             my $overloaded = sub {
11             my ($m) = @_;
12             overload::ov_method(overload::mycan(__PACKAGE__,'('.$m),__PACKAGE__);
13             };
14             overload->import( '""' => sub { $_[0]->toString() } ) unless $overloaded->('""');
15             overload->import( 'bool' => sub { 1 } ) unless $overloaded->('bool');
16             overload->import( '0+' => sub { Scalar::Util::refaddr($_[0]) } ) unless $overloaded->('0+');
17             overload->import( fallback => 1 );
18             }
19             }
20             {
21             package # hide
22             XML::LibXML::Element;
23             use overload ();
24             BEGIN {
25             my $overloaded = sub {
26             my ($m) = @_;
27             overload::ov_method(overload::mycan(__PACKAGE__,'('.$m),__PACKAGE__);
28             };
29             overload->import( '""' => sub { $_[0]->toString() } ) unless $overloaded->('""');
30             overload->import( fallback => 1 ) if $overloaded->('bool');
31            
32             }
33             }
34             package XML::Declare;
35              
36             use 5.008008;
37             use strict;
38             use warnings;
39             use Carp;
40              
41             =head1 NAME
42              
43             XML::Declare - Create XML documents with declaration style
44              
45             =cut
46              
47             our $VERSION = '0.06';
48              
49             =head1 SYNOPSIS
50              
51             my $doc = doc {
52             element feed => sub {
53             attr xmlns => 'http://www.w3.org/2005/Atom';
54             comment "generated using XML::Declare v$XML::Declare::VERSION";
55             for (1..3) {
56             element entry => sub {
57             element title => 'Title', type => 'text';
58             element content => sub {
59             attr type => 'text';
60             cdata 'Desc';
61             };
62             element published => '123123-1231-123-123';
63             element author => sub {
64             element name => 'Mons';
65             }
66             };
67             }
68             };
69             } '1.0','utf-8';
70              
71             print $doc;
72              
73             doc { DEFINITIONS } < args to XML::LibXML::Document->new >
74              
75             Where DEFINITIONS are
76            
77             element name => sub { DEFINITIONS }
78             or
79             element
80             name => 'TextContent',
81             attr => value,
82             attr1 => [qw(more values)];
83            
84             attr name => values;
85            
86             text $content;
87            
88             cdata $content;
89            
90             comment $content;
91              
92             =head1 EXPORT
93              
94             =head2 doc BLOCK [ $version, $charset ];
95              
96             Create L;
97              
98             =head2 element $name, sub { ... };
99              
100             Create L with name C<$name>; everything, called within C will be appended as children to this element
101              
102             =head2 element $name, ATTRS
103              
104             Create L with name C<$name> and set it's attributes. C is a pairs of C "value">
105              
106             =head2 attr $name, $value
107              
108             Create L with name C<$name> and value C<$value>
109              
110             =head2 text $content
111              
112             Create L node with content C<$content>
113              
114             =head2 cdata $content
115              
116             Create L node with content C<$content>
117              
118             =head2 comment $content
119              
120             Create L node with content C<$content>
121              
122             =cut
123              
124              
125             use strict;
126             use XML::LibXML;
127              
128             sub import {
129             my $caller = caller;
130             no strict 'refs';
131             *{ $caller . '::doc' } = \&doc;
132             *{ $caller . '::element' } = \&element;
133             *{ $caller . '::attr' } = \&attr;
134             *{ $caller . '::text' } = \&text;
135             *{ $caller . '::cdata' } = \&cdata;
136             *{ $caller . '::comment' } = \&comment;
137             }
138              
139             {
140             our $is_doc;
141             our $element;
142             sub element ($;$@);
143             sub attr (@);
144             sub _attr(@) {
145             eval {
146             $element->setAttribute(@_);
147             1;
148             } or do {
149             ( my $e = $@ ) =~ s{ at \S+? line \d+\.\s*$}{};
150             croak $e;
151             };
152             }
153             sub text ($);
154             sub _text ($) {
155             $element->appendChild(XML::LibXML::Text->new(shift));
156             }
157             sub cdata ($);
158             sub _cdata ($) {
159             $element->appendChild(XML::LibXML::CDATASection->new(shift));
160             }
161             sub comment ($);
162             sub _comment ($) {
163             local $_ = shift;
164             m{--}s and croak "'--' (double-hyphen) MUST NOT occur within comments";
165             substr($_,-1,1) eq '-' and croak "comment MUST NOT end with a '-' (hyphen)";
166             $element->appendChild(XML::LibXML::Comment->new($_));
167             }
168            
169             sub element($;$@) {
170             my $name = shift;
171             defined $element or
172             local *attr = \&_attr and
173             local *text = \&_text and
174             local *cdata = \&_cdata and
175             local *comment = \&_comment;
176             my ($code,$text);
177             if (@_) {
178             if (ref $_[-1] eq 'CODE') {
179             $code = pop;
180             } else {
181             $text = shift;
182             }
183             }
184             my $new;
185             {
186             #local $element = $doc->createElement($name);
187             local $element;
188             eval {
189             $new = XML::LibXML::Element->new($name);
190             $new->setNodeName($name); # Will invoke checks
191             1;
192             } or do {
193             ( my $e = $@ ) =~ s{ at \S+? line \d+\.\s*$}{};
194             croak $e;
195             };
196             $new->appendText($text) if defined $text;
197             while (my( $attr,$val ) = splice @_, 0, 2) {
198             $new->setAttribute($attr, ref $val eq 'ARRAY' ? @$val : $val);
199             }
200             if ($code) {{
201             local $element = $new;
202             local $is_doc;
203             $code->() if $code;
204             #$element->appendChild($_) for @EL;
205             }}
206             #push @EL,$element;
207             }
208             if (defined $is_doc) {
209             if ( $is_doc > 0 ) {
210             $element->appendChild($new);
211             } else {
212             $element->setDocumentElement($new);
213             $is_doc++;
214             }
215             return;
216             } elsif (defined $element) {
217             $element->appendChild($new);
218             return;
219             } else {
220             return $new;
221             }
222            
223             }
224            
225             sub doc (&;$$) {
226             my $code = shift;
227             my $version = shift || '1.0';
228             my $encoding = shift || 'utf-8';
229             my $doc = XML::LibXML::Document->new($version, $encoding);
230             my $oldwarn = $SIG{__WARN__};
231             local $SIG{__WARN__} = sub {
232             my $warn = shift;
233             substr($warn, rindex($warn, ' at '),-1,'');
234             chomp $warn;
235             local $SIG{__WARN__} = $oldwarn if defined $oldwarn;
236             Carp::carp $warn;
237             };
238             local $element = $doc;
239             no strict 'refs';
240             local *attr = \&_attr;
241             local *text = \&_text;
242             local *cdata = \&_cdata;
243             local *comment = \&_comment;
244             local $is_doc = 0;
245             $code->();
246             if ($is_doc == 0) {
247             Carp::carp "Empty document";
248             }
249             elsif ($is_doc > 1) {
250             Carp::carp "More than one root element. All except first are ignored";
251             }
252             $doc;
253             }
254             }
255              
256              
257             =head1 AUTHOR
258              
259             Mons Anderson
260              
261             =head1 LICENSE AND COPYRIGHT
262              
263             Copyright 2009-2010 Mons Anderson.
264              
265             This program is free software; you can redistribute it and/or modify it
266             under the terms of either: the GNU General Public License as published
267             by the Free Software Foundation; or the Artistic License.
268              
269             =cut
270              
271             1; # End of XML::Declare