File Coverage

blib/lib/XML/Easy/Classify.pm
Criterion Covered Total %
statement 82 82 100.0
branch 42 42 100.0
condition 15 15 100.0
subroutine 30 30 100.0
pod 16 16 100.0
total 185 185 100.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              
18             if(is_xml_name($arg)) { ...
19             check_xml_name($arg);
20             if(is_xml_encname($arg)) { ...
21             check_xml_encname($arg);
22             if(is_xml_chardata($arg)) { ...
23             check_xml_chardata($arg);
24              
25             if(is_xml_attributes($arg)) { ...
26             check_xml_attributes($arg);
27              
28             if(is_xml_content_object($arg)) { ...
29             check_xml_content_object($arg);
30             if(is_xml_content_twine($arg)) { ...
31             check_xml_content_twine($arg);
32             if(is_xml_content($arg)) { ...
33             check_xml_content($arg);
34              
35             if(is_xml_element($arg)) { ...
36             check_xml_element($arg);
37              
38             =head1 DESCRIPTION
39              
40             This module provides various type-testing functions, relating to data
41             types used in the L ensemble. These are mainly intended to be
42             used to enforce validity of data being processed by XML-related functions.
43              
44             There are two flavours of function in this module. Functions of the first
45             flavour only provide type classification, to allow code to discriminate
46             between argument types. Functions of the second flavour package up the
47             most common type of type discrimination: checking that an argument is
48             of an expected type. The functions come in matched pairs.
49              
50             =cut
51              
52             package XML::Easy::Classify;
53              
54 9     9   5143 { use 5.008; }
  9         36  
55 9     9   54 use warnings;
  9         21  
  9         246  
56 9     9   47 use strict;
  9         24  
  9         262  
57              
58 9     9   465 use Params::Classify 0.000 qw(is_string is_ref is_strictly_blessed);
  9         1935  
  9         552  
59             use XML::Easy::Syntax 0.000
60 9     9   4068 qw($xml10_char_rx $xml10_name_rx $xml10_encname_rx);
  9         371  
  9         2358  
61              
62             our $VERSION = "0.010";
63              
64 9     9   117 use parent "Exporter";
  9         25  
  9         78  
65             our @EXPORT_OK = qw(
66             is_xml_name check_xml_name
67             is_xml_encname check_xml_encname
68             is_xml_chardata check_xml_chardata
69             is_xml_attributes check_xml_attributes
70             is_xml_content_object check_xml_content_object
71             is_xml_content_twine check_xml_content_twine
72             is_xml_content_array
73             is_xml_content check_xml_content
74             is_xml_element check_xml_element
75             );
76              
77             sub _throw_data_error($) {
78 24252     24252   69559 my($msg) = @_;
79 24252         199679 die "invalid XML data: $msg\n";
80             }
81              
82             =head1 FUNCTIONS
83              
84             Each of these functions takes one scalar argument (I) to be tested.
85             Any scalar value is acceptable for the argument to be tested. Each C
86             function returns a simple truth value result, which is true iff I
87             is of the type being checked for. Each C function will return
88             normally if the argument is of the type being checked for, or will C
89             if it is not.
90              
91             =over
92              
93             =item is_xml_name(ARG)
94              
95             =item check_xml_name(ARG)
96              
97             Check whether I is a plain string satisfying the XML name syntax.
98             (Such names are used to identify element types, attributes, entities,
99             and other things in XML.)
100              
101             =cut
102              
103             sub is_xml_name($) {
104 9     9   1353 no warnings "utf8";
  9         24  
  9         1490  
105 18632   100 18632 1 655480 return is_string($_[0]) && $_[0] =~ /\A$xml10_name_rx\z/o;
106             }
107              
108             sub check_xml_name($) {
109 558 100   558 1 465066 _throw_data_error("name isn't a string") unless is_string($_[0]);
110 9     9   63 no warnings "utf8";
  9         21  
  9         682  
111 532 100       34695 _throw_data_error("illegal name")
112             unless $_[0] =~ /\A$xml10_name_rx\z/o;
113             }
114              
115             =item is_xml_encname(ARG)
116              
117             =item check_xml_encname(ARG)
118              
119             Check whether I is a plain string satisfying the XML character
120             encoding name syntax.
121              
122             =cut
123              
124             sub is_xml_encname($) {
125 9     9   56 no warnings "utf8";
  9         25  
  9         759  
126 578   100 578 1 384529 return is_string($_[0]) && $_[0] =~ /\A$xml10_encname_rx\z/o;
127             }
128              
129             sub check_xml_encname($) {
130 578 100   578 1 424513 _throw_data_error("encoding name isn't a string")
131             unless is_string($_[0]);
132 9     9   57 no warnings "utf8";
  9         19  
  9         610  
133 552 100       30106 _throw_data_error("illegal encoding name")
134             unless $_[0] =~ /\A$xml10_encname_rx\z/o;
135             }
136              
137             =item is_xml_chardata(ARG)
138              
139             =item check_xml_chardata(ARG)
140              
141             Check whether I is a plain string consisting of a sequence of
142             characters that are acceptable to XML. Such a string is valid as data
143             in an XML element (where it may be intermingled with subelements) or as
144             the value of an element attribute.
145              
146             =cut
147              
148             sub is_xml_chardata($) {
149 9     9   53 no warnings "utf8";
  9         23  
  9         746  
150 7236   100 7236 1 1359307 return is_string($_[0]) && $_[0] =~ /\A$xml10_char_rx*\z/o;
151             }
152              
153             sub check_xml_chardata($) {
154 364148 100   364148 1 1137451 _throw_data_error("character data isn't a string")
155             unless is_string($_[0]);
156 9     9   54 no warnings "utf8";
  9         54  
  9         1526  
157 363134 100       5784321 _throw_data_error("character data contains illegal character")
158             unless $_[0] =~ /\A$xml10_char_rx*\z/o;
159             }
160              
161             =item is_xml_attributes(ARG)
162              
163             =item check_xml_attributes(ARG)
164              
165             Check whether I is a reference to a hash that is well-formed as
166             an XML element attribute set. To be well-formed, each key in the hash
167             must be an XML name string, and each value must be an XML character
168             data string.
169              
170             =cut
171              
172             sub is_xml_attributes($) {
173 1186 100   1186 1 689435 return undef unless is_ref($_[0], "HASH");
174 1154         3033 my $attrs = $_[0];
175 1154         5192 foreach(keys %$attrs) {
176             return undef unless
177 1350 100 100     4186 is_xml_name($_) && is_xml_chardata($attrs->{$_});
178             }
179 444         2484 return 1;
180             }
181              
182             sub check_xml_attributes($) {
183 183033 100   183033 1 2527260 _throw_data_error("attribute hash isn't a hash")
184             unless is_ref($_[0], "HASH");
185 183001         296511 foreach(sort keys %{$_[0]}) {
  183001         712175  
186 9     9   60 no warnings "utf8";
  9         22  
  9         4115  
187 15977 100       543943 _throw_data_error("illegal attribute name")
188             unless /\A$xml10_name_rx\z/o;
189 7535         23953 check_xml_chardata($_[0]->{$_});
190             }
191             }
192              
193             =item is_xml_content_object(ARG)
194              
195             =item check_xml_content_object(ARG)
196              
197             Check whether I is a reference to an L
198             object, and thus represents a chunk of XML content.
199              
200             =cut
201              
202             sub is_xml_content_object($) {
203 343421     343421 1 1172055 return is_strictly_blessed($_[0], "XML::Easy::Content");
204             }
205              
206             sub check_xml_content_object($) {
207 330783 100   330783 1 593544 _throw_data_error("content data isn't a content chunk")
208             unless &is_xml_content_object;
209             }
210              
211             =item is_xml_content_twine(ARG)
212              
213             =item check_xml_content_twine(ARG)
214              
215             Check whether I is a reference to a twine array
216             (see L),
217             and thus represents a chunk of XML content.
218              
219             =cut
220              
221             sub is_xml_element($);
222              
223             sub is_xml_content_twine($) {
224 3838 100   3838 1 1158719 return undef unless is_ref($_[0], "ARRAY");
225 3780         8840 my $twine = $_[0];
226 3780 100       12659 return undef unless @$twine % 2 == 1;
227 3772         10324 for(my $i = $#$twine; ; $i--) {
228 5712 100       15367 return undef unless is_xml_chardata($twine->[$i]);
229 4116 100       17028 last if $i-- == 0;
230 2004 100       6615 return undef unless is_xml_element($twine->[$i]);
231             }
232 2112         11515 return 1;
233             }
234              
235             sub check_xml_element($);
236              
237             sub check_xml_content_twine($) {
238 178238 100   178238 1 1531851 _throw_data_error("content array isn't an array")
239             unless is_ref($_[0], "ARRAY");
240 178208         283769 my $twine = $_[0];
241 178208 100       441012 _throw_data_error("content array has even length")
242             unless @$twine % 2 == 1;
243 178112         300266 for(my $i = 0; ; $i++) {
244 344575         840134 check_xml_chardata($twine->[$i]);
245 338191 100       933742 last if ++$i == @$twine;
246 167231         312819 check_xml_element($twine->[$i]);
247             }
248             }
249              
250             =item is_xml_content_array(ARG)
251              
252             Deprecated alias for L.
253              
254             =cut
255              
256             *is_xml_content_array = \&is_xml_content_twine;
257              
258             =item is_xml_content(ARG)
259              
260             =item check_xml_content(ARG)
261              
262             Check whether I is a reference to either an L
263             object or a twine array (see L),
264             and thus represents a chunk of XML content.
265              
266             =cut
267              
268             sub is_xml_content($) {
269 1920   100 1920 1 1174350 return &is_xml_content_object || &is_xml_content_twine;
270             }
271              
272             sub check_xml_content($) {
273 1690 100   1690 1 1243418 if(is_ref($_[0], "ARRAY")) {
274 1660         4902 &check_xml_content_twine;
275             } else {
276 30         98 &check_xml_content_object;
277             }
278             }
279              
280             =item is_xml_element(ARG)
281              
282             =item check_xml_element(ARG)
283              
284             Check whether I is a reference to an L
285             object, and thus represents an XML element.
286              
287             =cut
288              
289 183279     183279 1 571757 sub is_xml_element($) { is_strictly_blessed($_[0], "XML::Easy::Element") }
290              
291             sub check_xml_element($) {
292 168419 100   168419 1 300528 _throw_data_error("element data isn't an element")
293             unless &is_xml_element;
294             }
295              
296             =back
297              
298             =head1 SEE ALSO
299              
300             L,
301             L
302              
303             =head1 AUTHOR
304              
305             Andrew Main (Zefram)
306              
307             =head1 COPYRIGHT
308              
309             Copyright (C) 2009, 2010, 2011, 2017
310             Andrew Main (Zefram)
311              
312             =head1 LICENSE
313              
314             This module is free software; you can redistribute it and/or modify it
315             under the same terms as Perl itself.
316              
317             =cut
318              
319             1;