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   622961 { use 5.010001; }
  9         42  
54 9     9   56 use warnings;
  9         18  
  9         591  
55 9     9   55 use strict;
  9         51  
  9         418  
56              
57 9     9   673 use Params::Classify 0.000 qw(is_string is_ref is_strictly_blessed);
  9         3265  
  9         805  
58             use XML::Easy::Syntax 0.000
59 9     9   5666 qw($xml10_char_rx $xml10_name_rx $xml10_encname_rx);
  9         326  
  9         5086  
60              
61             our $VERSION = "0.014";
62              
63 9     9   86 use parent "Exporter";
  9         40  
  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 23248     23248   64814 my($msg) = @_;
78 23248         436693 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   1833 no if "$]" < 5.017002, qw(warnings utf8);
  9         17  
  9         668  
104 9   33 9   92 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         46  
  9         1233  
105 18084   100 18084 1 920115 return is_string($_[0]) && $_[0] =~ /\A$xml10_name_rx\z/o;
106             }
107              
108             sub check_xml_name($) {
109 548 100   548 1 516546 _throw_data_error("name isn't a string") unless is_string($_[0]);
110 9     9   92 no if "$]" < 5.017002, qw(warnings utf8);
  9         22  
  9         548  
111 9   33 9   47 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         47  
  9         950  
112 522 100       79303 _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   53 no if "$]" < 5.017002, qw(warnings utf8);
  9         16  
  9         476  
127 9   33 9   68 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         16  
  9         1092  
128 568   100 568 1 338012 return is_string($_[0]) && $_[0] =~ /\A$xml10_encname_rx\z/o;
129             }
130              
131             sub check_xml_encname($) {
132 568 100   568 1 651965 _throw_data_error("encoding name isn't a string")
133             unless is_string($_[0]);
134 9     9   55 no if "$]" < 5.017002, qw(warnings utf8);
  9         15  
  9         429  
135 9   33 9   44 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         43  
  9         905  
136 542 100       30826 _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   50 no if "$]" < 5.017002, qw(warnings utf8);
  9         14  
  9         415  
153 9   33 9   41 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         14  
  9         1074  
154 7076   100 7076 1 1439507 return is_string($_[0]) && $_[0] =~ /\A$xml10_char_rx*\z/o;
155             }
156              
157             sub check_xml_chardata($) {
158 363127 100   363127 1 1352355 _throw_data_error("character data isn't a string")
159             unless is_string($_[0]);
160 9     9   48 no if "$]" < 5.017002, qw(warnings utf8);
  9         17  
  9         576  
161 9   33 9   59 no if "$]" >= 5.023006 && "$]" < 5.027001, qw(warnings deprecated);
  9         15  
  9         4236  
162 362113 100       8257226 _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 1160 100   1160 1 454356 return undef unless is_ref($_[0], "HASH");
179 1128         2281 my $attrs = $_[0];
180 1128         3247 foreach(keys %$attrs) {
181             return undef unless
182 1324 100 100     3176 is_xml_name($_) && is_xml_chardata($attrs->{$_});
183             }
184 444         2058 return 1;
185             }
186              
187             sub check_xml_attributes($) {
188 182428 100   182428 1 2879466 _throw_data_error("attribute hash isn't a hash")
189             unless is_ref($_[0], "HASH");
190 182396         296106 foreach(sort keys %{$_[0]}) {
  182396         727772  
191 9     9   89 no if "$]" < 5.017002, qw(warnings utf8);
  9         961  
  9         529  
192 9   33     5284 no if "$]" >= 5.023006 && "$]" < 5.027001,
193 9     9   47 qw(warnings deprecated);
  9         16  
194 15529 100       1199414 _throw_data_error("illegal attribute name")
195             unless /\A$xml10_name_rx\z/o;
196 7255         22014 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 342925     342925 1 1096590 return is_strictly_blessed($_[0], "XML::Easy::Content");
211             }
212              
213             sub check_xml_content_object($) {
214 330719 100   330719 1 619820 _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 3742 100   3742 1 843659 return undef unless is_ref($_[0], "ARRAY");
232 3684         6519 my $twine = $_[0];
233 3684 100       10917 return undef unless @$twine % 2 == 1;
234 3676         7747 for(my $i = $#$twine; ; $i--) {
235 5584 100       12339 return undef unless is_xml_chardata($twine->[$i]);
236 4084 100       12298 last if $i-- == 0;
237 1972 100       4180 return undef unless is_xml_element($twine->[$i]);
238             }
239 2112         8206 return 1;
240             }
241              
242             sub check_xml_element($);
243              
244             sub check_xml_content_twine($) {
245 177849 100   177849 1 2085130 _throw_data_error("content array isn't an array")
246             unless is_ref($_[0], "ARRAY");
247 177819         271939 my $twine = $_[0];
248 177819 100       450008 _throw_data_error("content array has even length")
249             unless @$twine % 2 == 1;
250 177723         303639 for(my $i = 0; ; $i++) {
251 344186         853661 check_xml_chardata($twine->[$i]);
252 338186 100       929836 last if ++$i == @$twine;
253 167231         295061 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 1872   100 1872 1 597118 return &is_xml_content_object || &is_xml_content_twine;
277             }
278              
279             sub check_xml_content($) {
280 1658 100   1658 1 1482378 if(is_ref($_[0], "ARRAY")) {
281 1628         3558 &check_xml_content_twine;
282             } else {
283 30         83 &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 182853     182853 1 526247 sub is_xml_element($) { is_strictly_blessed($_[0], "XML::Easy::Element") }
297              
298             sub check_xml_element($) {
299 168409 100   168409 1 298331 _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;