File Coverage

blib/lib/XML/Easy/Classify.pm
Criterion Covered Total %
statement 103 103 100.0
branch 42 42 100.0
condition 22 36 61.1
subroutine 37 37 100.0
pod 16 16 100.0
total 220 234 94.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             XML::Easy::Classify - classification of XML-related items
4              
5             =head1 SYNOPSIS
6              
7             use XML::Easy::Classify qw(
8             is_xml_name check_xml_name
9             is_xml_encname check_xml_encname
10             is_xml_chardata check_xml_chardata
11             is_xml_attributes check_xml_attributes
12             is_xml_content_object check_xml_content_object
13             is_xml_content_twine check_xml_content_twine
14             is_xml_content check_xml_content
15             is_xml_element check_xml_element);
16              
17             if(is_xml_name($arg)) { ...
18             check_xml_name($arg);
19             if(is_xml_encname($arg)) { ...
20             check_xml_encname($arg);
21             if(is_xml_chardata($arg)) { ...
22             check_xml_chardata($arg);
23              
24             if(is_xml_attributes($arg)) { ...
25             check_xml_attributes($arg);
26              
27             if(is_xml_content_object($arg)) { ...
28             check_xml_content_object($arg);
29             if(is_xml_content_twine($arg)) { ...
30             check_xml_content_twine($arg);
31             if(is_xml_content($arg)) { ...
32             check_xml_content($arg);
33              
34             if(is_xml_element($arg)) { ...
35             check_xml_element($arg);
36              
37             =head1 DESCRIPTION
38              
39             This module provides various type-testing functions, relating to data
40             types used in the L ensemble. These are mainly intended to be
41             used to enforce validity of data being processed by XML-related functions.
42              
43             There are two flavours of function in this module. Functions of the first
44             flavour only provide type classification, to allow code to discriminate
45             between argument types. Functions of the second flavour package up the
46             most common type of type discrimination: checking that an argument is
47             of an expected type. The functions come in matched pairs.
48              
49             =cut
50              
51             package XML::Easy::Classify;
52              
53 9     9   6768 { use 5.008; }
  9         37  
54 9     9   56 use warnings;
  9         22  
  9         276  
55 9     9   59 use strict;
  9         20  
  9         323  
56              
57 9     9   809 use Params::Classify 0.000 qw(is_string is_ref is_strictly_blessed);
  9         3289  
  9         635  
58             use XML::Easy::Syntax 0.000
59 9     9   4194 qw($xml10_char_rx $xml10_name_rx $xml10_encname_rx);
  9         372  
  9         2273  
60              
61             our $VERSION = "0.011";
62              
63 9     9   96 use parent "Exporter";
  9         23  
  9         61  
64             our @EXPORT_OK = qw(
65             is_xml_name check_xml_name
66             is_xml_encname check_xml_encname
67             is_xml_chardata check_xml_chardata
68             is_xml_attributes check_xml_attributes
69             is_xml_content_object check_xml_content_object
70             is_xml_content_twine check_xml_content_twine
71             is_xml_content_array
72             is_xml_content check_xml_content
73             is_xml_element check_xml_element
74             );
75              
76             sub _throw_data_error($) {
77 25256     25256   61207 my($msg) = @_;
78 25256         195151 die "invalid XML data: $msg\n";
79             }
80              
81             =head1 FUNCTIONS
82              
83             Each of these functions takes one scalar argument (I) to be tested.
84             Any scalar value is acceptable for the argument to be tested. Each C
85             function returns a simple truth value result, which is true iff I
86             is of the type being checked for. Each C function will return
87             normally if the argument is of the type being checked for, or will C
88             if it is not.
89              
90             =over
91              
92             =item is_xml_name(ARG)
93              
94             =item check_xml_name(ARG)
95              
96             Check whether I is a plain string satisfying the XML name syntax.
97             (Such names are used to identify element types, attributes, entities,
98             and other things in XML.)
99              
100             =cut
101              
102             sub is_xml_name($) {
103 9     9   6461 no if "$]" < 5.017002, qw(warnings utf8);
  9         88  
  9         77  
104 9   33 9   484 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         17  
  9         96  
105 19180   100 19180 1 564924 return is_string($_[0]) && $_[0] =~ /\A$xml10_name_rx\z/o;
106             }
107              
108             sub check_xml_name($) {
109 568 100   568 1 383261 _throw_data_error("name isn't a string") unless is_string($_[0]);
110 9     9   1314 no if "$]" < 5.017002, qw(warnings utf8);
  9         17  
  9         47  
111 9   33 9   386 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         18  
  9         78  
112 542 100       27059 _throw_data_error("illegal name")
113             unless $_[0] =~ /\A$xml10_name_rx\z/o;
114             }
115              
116             =item is_xml_encname(ARG)
117              
118             =item check_xml_encname(ARG)
119              
120             Check whether I is a plain string satisfying the XML character
121             encoding name syntax.
122              
123             =cut
124              
125             sub is_xml_encname($) {
126 9     9   953 no if "$]" < 5.017002, qw(warnings utf8);
  9         23  
  9         48  
127 9   33 9   426 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         63  
  9         81  
128 588   100 588 1 228812 return is_string($_[0]) && $_[0] =~ /\A$xml10_encname_rx\z/o;
129             }
130              
131             sub check_xml_encname($) {
132 588 100   588 1 412793 _throw_data_error("encoding name isn't a string")
133             unless is_string($_[0]);
134 9     9   1012 no if "$]" < 5.017002, qw(warnings utf8);
  9         16  
  9         53  
135 9   33 9   421 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         19  
  9         99  
136 562 100       22298 _throw_data_error("illegal encoding name")
137             unless $_[0] =~ /\A$xml10_encname_rx\z/o;
138             }
139              
140             =item is_xml_chardata(ARG)
141              
142             =item check_xml_chardata(ARG)
143              
144             Check whether I is a plain string consisting of a sequence of
145             characters that are acceptable to XML. Such a string is valid as data
146             in an XML element (where it may be intermingled with subelements) or as
147             the value of an element attribute.
148              
149             =cut
150              
151             sub is_xml_chardata($) {
152 9     9   942 no if "$]" < 5.017002, qw(warnings utf8);
  9         17  
  9         43  
153 9   33 9   363 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         15  
  9         73  
154 7396   100 7396 1 1075808 return is_string($_[0]) && $_[0] =~ /\A$xml10_char_rx*\z/o;
155             }
156              
157             sub check_xml_chardata($) {
158 365169 100   365169 1 1047973 _throw_data_error("character data isn't a string")
159             unless is_string($_[0]);
160 9     9   1124 no if "$]" < 5.017002, qw(warnings utf8);
  9         19  
  9         46  
161 9   33 9   426 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         18  
  9         79  
162 364155 100       5312252 _throw_data_error("character data contains illegal character")
163             unless $_[0] =~ /\A$xml10_char_rx*\z/o;
164             }
165              
166             =item is_xml_attributes(ARG)
167              
168             =item check_xml_attributes(ARG)
169              
170             Check whether I is a reference to a hash that is well-formed as
171             an XML element attribute set. To be well-formed, each key in the hash
172             must be an XML name string, and each value must be an XML character
173             data string.
174              
175             =cut
176              
177             sub is_xml_attributes($) {
178 1212 100   1212 1 373484 return undef unless is_ref($_[0], "HASH");
179 1180         1944 my $attrs = $_[0];
180 1180         3622 foreach(keys %$attrs) {
181             return undef unless
182 1376 100 100     2818 is_xml_name($_) && is_xml_chardata($attrs->{$_});
183             }
184 444         1713 return 1;
185             }
186              
187             sub check_xml_attributes($) {
188 183638 100   183638 1 2146641 _throw_data_error("attribute hash isn't a hash")
189             unless is_ref($_[0], "HASH");
190 183606         257885 foreach(sort keys %{$_[0]}) {
  183606         699820  
191 9     9   1819 no if "$]" < 5.017002, qw(warnings utf8);
  9         20  
  9         44  
192 9   33     89 no if "$]" >= 5.023006 && "$]" < 5.027001,
193 9     9   405 qw(warnings deprecated);
  9         17  
194 16425 100       515285 _throw_data_error("illegal attribute name")
195             unless /\A$xml10_name_rx\z/o;
196 7815         20661 check_xml_chardata($_[0]->{$_});
197             }
198             }
199              
200             =item is_xml_content_object(ARG)
201              
202             =item check_xml_content_object(ARG)
203              
204             Check whether I is a reference to an L
205             object, and thus represents a chunk of XML content.
206              
207             =cut
208              
209             sub is_xml_content_object($) {
210 343917     343917 1 1107794 return is_strictly_blessed($_[0], "XML::Easy::Content");
211             }
212              
213             sub check_xml_content_object($) {
214 330847 100   330847 1 571270 _throw_data_error("content data isn't a content chunk")
215             unless &is_xml_content_object;
216             }
217              
218             =item is_xml_content_twine(ARG)
219              
220             =item check_xml_content_twine(ARG)
221              
222             Check whether I is a reference to a twine array
223             (see L),
224             and thus represents a chunk of XML content.
225              
226             =cut
227              
228             sub is_xml_element($);
229              
230             sub is_xml_content_twine($) {
231 3934 100   3934 1 872258 return undef unless is_ref($_[0], "ARRAY");
232 3876         6869 my $twine = $_[0];
233 3876 100       9922 return undef unless @$twine % 2 == 1;
234 3868         8026 for(my $i = $#$twine; ; $i--) {
235 5840 100       12567 return undef unless is_xml_chardata($twine->[$i]);
236 4148 100       12695 last if $i-- == 0;
237 2036 100       4641 return undef unless is_xml_element($twine->[$i]);
238             }
239 2112         8570 return 1;
240             }
241              
242             sub check_xml_element($);
243              
244             sub check_xml_content_twine($) {
245 178627 100   178627 1 1654551 _throw_data_error("content array isn't an array")
246             unless is_ref($_[0], "ARRAY");
247 178597         252766 my $twine = $_[0];
248 178597 100       403291 _throw_data_error("content array has even length")
249             unless @$twine % 2 == 1;
250 178501         269596 for(my $i = 0; ; $i++) {
251 344964         746253 check_xml_chardata($twine->[$i]);
252 338196 100       827304 last if ++$i == @$twine;
253 167231         262774 check_xml_element($twine->[$i]);
254             }
255             }
256              
257             =item is_xml_content_array(ARG)
258              
259             Deprecated alias for L.
260              
261             =cut
262              
263             *is_xml_content_array = \&is_xml_content_twine;
264              
265             =item is_xml_content(ARG)
266              
267             =item check_xml_content(ARG)
268              
269             Check whether I is a reference to either an L
270             object or a twine array (see L),
271             and thus represents a chunk of XML content.
272              
273             =cut
274              
275             sub is_xml_content($) {
276 1968   100 1968 1 678824 return &is_xml_content_object || &is_xml_content_twine;
277             }
278              
279             sub check_xml_content($) {
280 1722 100   1722 1 1201663 if(is_ref($_[0], "ARRAY")) {
281 1692         3460 &check_xml_content_twine;
282             } else {
283 30         80 &check_xml_content_object;
284             }
285             }
286              
287             =item is_xml_element(ARG)
288              
289             =item check_xml_element(ARG)
290              
291             Check whether I is a reference to an L
292             object, and thus represents an XML element.
293              
294             =cut
295              
296 183705     183705 1 511339 sub is_xml_element($) { is_strictly_blessed($_[0], "XML::Easy::Element") }
297              
298             sub check_xml_element($) {
299 168429 100   168429 1 240068 _throw_data_error("element data isn't an element")
300             unless &is_xml_element;
301             }
302              
303             =back
304              
305             =head1 SEE ALSO
306              
307             L,
308             L
309              
310             =head1 AUTHOR
311              
312             Andrew Main (Zefram)
313              
314             =head1 COPYRIGHT
315              
316             Copyright (C) 2009, 2010, 2011, 2017
317             Andrew Main (Zefram)
318              
319             =head1 LICENSE
320              
321             This module is free software; you can redistribute it and/or modify it
322             under the same terms as Perl itself.
323              
324             =cut
325              
326             1;