File Coverage

blib/lib/Simple/SAX/Serializer/Handler.pm
Criterion Covered Total %
statement 111 135 82.2
branch 12 28 42.8
condition 31 85 36.4
subroutine 25 28 89.2
pod 10 10 100.0
total 189 286 66.0


line stmt bran cond sub pod time code
1             package Simple::SAX::Serializer::Handler;
2              
3 2     2   38545 use strict;
  2         5  
  2         81  
4 2     2   12 use warnings;
  2         5  
  2         75  
5 2     2   12 use vars qw(@EXPORT_OK %EXPORT_TAGS $VERSION);
  2         3  
  2         157  
6 2     2   10 use base 'Exporter';
  2         5  
  2         4078  
7              
8             $VERSION = 0.02;
9              
10             @EXPORT_OK = qw(array_handler array_of_objects_handler hash_handler hash_item_of_child_value_handler hash_of_object_array_handler hash_of_array_handler ignore_node_handler root_object_handler object_handler custom_array_handler);
11             %EXPORT_TAGS = (all => \@EXPORT_OK);
12              
13              
14             =head1 NAME
15              
16             Simple::SAX::Serializer::Handler - Collections of the mapping handlers for Simple::SAX::Serializer.
17              
18             =head1 SYNOPSIS
19              
20             use Simple::SAX::Serializer::Handler ':all';
21             use Simple::SAX::Serializer;
22              
23             my $xml = Simple::SAX::Serializer->new;
24             $xml->handler('node', array_handler());
25             ...
26             my $result = $xml->parse_string($xml_content);
27              
28              
29             =head1 DESCRIPTION
30              
31             Collections of the mapping handlers for Simple::SAX::Serializer.
32              
33             =head1 EXPORT
34              
35             array_handler
36             array_of_objects_handler
37             hash_handler
38             hash_item_of_child_value_handler
39             hash_of_object_array_handler
40             hash_of_array_handler
41             ignore_node_handler
42             custom_array_handler
43             object_handler
44             root_object_handler by ':all' tag
45              
46             =head2 METHODS
47              
48             =over
49              
50             =cut
51              
52             =item array_handler
53              
54             Takes optionally storage key to the array(by default the element name).
55             Returns handler for transforming nodes value into array
56              
57             my $xml_content = <
58            
59            
60             value1
61             value2
62             value1
63             value2
64            
65             XML
66              
67              
68             my $xml = Simple::SAX::Serializer->new;
69              
70             $xml->handler('node', array_handler());
71             $xml->handler('nodeA', array_handler());
72             $xml->handler('root', sub {
73             my ($self, $element, $parent) = @_;
74             my $attributes = $element->attributes;
75             my $result = $element->children_result;
76             });
77             my $result = $xml->parse_string($xml_content);
78             #transforms $result to {{node => ['value1' ,'value2'], nodeA => ['value1', 'value2']}
79              
80              
81             =cut
82              
83             sub array_handler {
84 3     3 1 312 my ($parent_key) = @_;
85             sub {
86 6     6   9 my ($self, $element, $parent) = @_;
87 6         21 my $result = $parent->children_hash_result;
88 6   33     29 my $key = $parent_key || $element->name;
89 6   100     27 my $array = $result->{$key} ||= [];
90 6         22 push @$array, $element->value(1);
91 3         23 };
92             }
93              
94             =item array_of_objects_handler
95              
96             Returns handler for transforming nodes attribute into array of the objects.
97             Takes class name or constructor code reference as parameter,
98             array ref of the required attributes, hash_ref of the optional attributes,
99              
100             my $xml_content = <
101            
102            
103            
104            
105            
106            
107            
108             XML
109              
110             package Object1;
111             sub new {
112             my $class = shift;
113             bless {@_}, $class
114             };
115              
116             package Object2;
117             sub new {
118             my $class = shift;
119             bless {@_}, $class
120             };
121              
122             sub object2{
123             Object2->new(@_);
124             }
125              
126             my $xml = Simple::SAX::Serializer->new;
127              
128             $xml->handler('object1', ::array_of_objects_handler('Object1', ['attr1']));
129             $xml->handler('object2', ::array_of_objects_handler(\&object2, ['attr1']));
130             $xml->handler('root', sub {
131             my ($self, $element, $parent) = @_;
132             my $attributes = $element->attributes;
133             $element->children_result;
134             });
135             my $result = $xml->parse_string($xml_content);
136              
137             #transforms $result to [
138             Object1->new(attr1 => 1),
139             Object1->new(attr1 => 2),
140             Object2->new(attr1 => 3),
141             Object2->new(attr1 => 4),
142             ];
143              
144             =cut
145              
146             sub array_of_objects_handler {
147 5     5 1 1715 my ($object_constructor, $required_attributes, $optional_attributes) = @_;
148 5         6 my $result;
149 5 100       14 if (ref($object_constructor) eq 'CODE') {
150             $result = sub {
151 2     2   4 my ($self, $element, $parent) = @_;
152 2 50 33     16 $element->validate_attributes($required_attributes, $optional_attributes)
153             if ($required_attributes || $optional_attributes);
154 2   50     7 my $children_result = $element->children_result || {};
155 2         8 my $attributes = $element->attributes;
156 2         6 my $result = $parent->children_array_result;
157 2         11 push @$result, $object_constructor->(%$attributes, %$children_result);
158             }
159 1         6 } else {
160             $result = sub {
161 8     8   14 my ($self, $element, $parent) = @_;
162 8 50 33     42 $element->validate_attributes($required_attributes, $optional_attributes)
163             if ($required_attributes || $optional_attributes);
164 8   50     27 my $children_result = $element->children_result || {};
165 8         26 my $attributes = $element->attributes;
166 8         22 my $result = $parent->children_array_result;
167 8         44 push @$result, $object_constructor->new(%$attributes, %$children_result);
168             }
169 4         17 }
170 5         30 $result;
171             }
172              
173              
174              
175             =item hash_of_object_array_handler
176              
177             Returns handler for transforming nodes attribute into array of the objects, that
178             is stored as hash item of the parent node.
179             Takes class name or constructor code reference as parameter,
180             array ref of the required attributes, hash_ref of the optional attributes,
181             storage key to the array(by default the element name).
182              
183             my $xml_content = <
184            
185            
186            
187            
188            
189             XML
190              
191             my $xml = Simple::SAX::Serializer->new;
192              
193             $xml->handler('object1', hash_of_object_array_handler('Object1', ['attr1']));
194             $xml->handler('root', sub {
195             my ($self, $element, $parent) = @_;
196             my $attributes = $element->attributes;
197             $element->children_result;
198             });
199             my $result = $xml->parse_string($xml_content);
200              
201             #transforms $result to [
202             Object1->new(attr1 => 1),
203             Object1->new(attr1 => 2),
204             Object2->new(attr1 => 3),
205             Object2->new(attr1 => 4),
206             ];
207              
208             =cut
209              
210             sub hash_of_object_array_handler {
211 1     1 1 1325 my ($object_constructor, $required_attributes, $optional_attributes, $parent_key) = @_;
212 1         3 my $result;
213 1 50       6 if (ref($object_constructor) eq 'CODE') {
214             $result = sub {
215 0     0   0 my ($self, $element, $parent) = @_;
216 0 0 0     0 $element->validate_attributes($required_attributes, $optional_attributes)
217             if ($required_attributes || $optional_attributes);
218 0   0     0 my $children_result = $element->children_result || {};
219 0         0 my $attributes = $element->attributes;
220 0         0 my $result = $parent->children_hash_result;
221 0   0     0 my $key = $parent_key || $element->name;
222 0   0     0 my $array = $result->{$key} ||= [];
223 0         0 push @$array, $object_constructor->(%$attributes, %$children_result);
224             }
225 0         0 } else {
226             $result = sub {
227 2     2   5 my ($self, $element, $parent) = @_;
228 2 50 33     15 $element->validate_attributes($required_attributes, $optional_attributes)
229             if ($required_attributes || $optional_attributes);
230 2   50     7 my $children_result = $element->children_result || {};
231 2         9 my $attributes = $element->attributes;
232 2         8 my $result = $parent->children_hash_result;
233 2   33     11 my $key = $parent_key || $element->name;
234 2   100     19 my $array = $result->{$key} ||= [];
235 2         13 push @$array, $object_constructor->new(%$attributes, %$children_result);
236             }
237 1         8 }
238 1         32 $result;
239             }
240              
241              
242             =item hash_of_array_handler
243              
244             Returns handler for transforming nodes attribute into array of the hash items, that
245             is stored as hash item of the parent node.
246             Takes array ref of the required attributes, hash_ref of the optional attributes,
247             storage key to the array(by default the element name).
248              
249             my $xml_content = <
250            
251            
252            
253            
254            
255             XML
256              
257             my $xml = Simple::SAX::Serializer->new;
258              
259             $xml->handler('object1', hash_of_array_handler(['attr1']));
260             $xml->handler('root', root_object_handler('Root'));
261              
262             my $result = $xml->parse_string($xml_content);
263             #converts result to
264             Root->new(object1 => [{attr1 => 1}, {attr1 => 2}]);
265              
266             =cut
267              
268             sub hash_of_array_handler {
269 1     1 1 1819 my ($required_attributes, $optional_attributes, $parent_key) = @_;
270             sub {
271 2     2   5 my ($self, $element, $parent) = @_;
272 2 50 33     12 $element->validate_attributes($required_attributes, $optional_attributes)
273             if ($required_attributes || $optional_attributes);
274 2   50     7 my $children_result = $element->children_result || {};
275 2         7 my $attributes = $element->attributes;
276 2         8 my $result = $parent->children_hash_result;
277 2   33     12 my $key = $parent_key || $element->name;
278 2   100     10 my $array = $result->{$key} ||= [];
279 2         11 push @$array, {%$attributes, %$children_result};
280             }
281 1         11 }
282              
283              
284             =item hash_handler
285              
286             Takes optionally parent storage key to the hash item (by default the element name).
287             optionally attribute name for the hash key (by default name).
288             Returns handler for transforming node into hash item.
289             Key of the hash is evaluated from the name node's attribute.
290             Value of the hash is evaluated from the node's value.
291              
292             my $xml_content = <
293            
294            
295             value1
296             value2
297             value3
298            
299             XML
300              
301             my $xml = Simple::SAX::Serializer->new;
302             $xml->handler('node', hash_handler());
303             $xml->handler('root', root_object_handler('Root'));
304             my $result = $xml->parse_string($xml_content);
305              
306             #transforms $result to Root->new(node => {key1 => 'value1', key2 => 'value2', key3 => 'value3'})
307              
308             =cut
309              
310             sub hash_handler {
311 1     1 1 2328 my ($parent_key, $hash_key_attribute) = @_;
312             sub {
313 3     3   5 my ($self, $element, $parent) = @_;
314 3   50     14 my $hash_key = $hash_key_attribute || 'name';
315 3         19 $element->validate_attributes([$hash_key]);
316 3         10 my $attributes = $element->attributes;
317 3         10 my $result = $parent->children_hash_result;
318 3   33     14 my $key = $parent_key || $element->name;
319 3   100     23 my $hash = $result->{$key} ||= {};
320 3         10 $hash->{$attributes->{$hash_key}} = $element->value(1);
321 1         12 };
322             };
323              
324              
325             =item hash_item_of_child_value_handler
326              
327             Takes optionally parent storage key to the hash item (by default the element name).
328             Returns handler for transforming child node value into hash value
329             Key of the hash is evaluated from current element name.
330              
331              
332             my $xml_content = <
333            
334            
335            
336            
337            
338            
339            
340            
341            
342            
343            
344             XML
345              
346             my $xml = Simple::SAX::Serializer->new;
347             $xml->handler('objects', hash_item_of_child_value_handler());
348             $xml->handler('object1', array_of_objects_handler('Object1'));
349              
350             $xml->handler('objects2', hash_item_of_child_value_handler());
351             $xml->handler('object2', array_of_objects_handler('Object2'));
352             $xml->handler('root', sub {
353             my ($self, $element, $parent) = @_;
354             my $attributes = $element->attributes;
355             $element->children_result;
356             });
357             my $result = $xml->parse_string($xml_content);
358             #transforms $result to {
359             objects => [Object1->new(attr1 => 1), Object1->new(attr1 => 2),],
360             objects2 => [Object2->new(attr1 => 3), Object2->new(attr1 => 4),]
361             };
362              
363             =cut
364              
365              
366             sub hash_item_of_child_value_handler {
367 3     3 1 6025 my ($parent_key) = @_;
368             sub {
369 3     3   6 my ($self, $element, $parent) = @_;
370 3         10 my $columns = $element->children_result;
371 3         10 my $result = $parent->children_hash_result;
372 3   33     14 my $key = $parent_key || $element->name;
373 3         12 $result->{$key} = $columns;
374             }
375 3         24 }
376              
377              
378             =item root_object_handler
379              
380             Returns handler for transforming root node into an object,
381              
382             Takes class name or constructor code reference, optionally code reference to customize return values,
383             array ref of the required attributes, hash_ref of the optional attributes,
384              
385             my $xml_content = <
386            
387            
388            
389            
390            
391            
392             3
393             4
394              
395            
396             XML
397              
398             {
399             package Root;
400             sub new {
401             my $class = shift;
402             bless {@_}, $class
403             };
404             }
405              
406             my $xml = Simple::SAX::Serializer->new;
407             $xml->handler('objects', hash_item_of_child_value_handler());
408             $xml->handler('object1', array_of_objects_handler('Object1'));
409             $xml->handler('object2', array_handler());
410             $xml->handler('root', root_object_handler('Root'));
411              
412             #transforms $result to
413             Root->new(
414             attr1 => 1, attr2 => 2,
415             objects => [Object1->new(attr1 => 1), Object1->new(attr1 => 2),],
416             object2 => [3, 4]
417             );
418              
419             =cut
420              
421             sub root_object_handler {
422 5     5 1 1632 my ($object_constructor, $code, $required_attributes, $optional_attributes) = @_;
423 5         6 my $result;
424 5 50       17 if (ref($object_constructor) eq 'CODE') {
425             $result = sub {
426 0     0   0 my ($self, $element, $parent) = @_;
427 0         0 my $args = $self->root_args;
428 0 0 0     0 $element->validate_attributes($required_attributes, $optional_attributes)
429             if ($required_attributes || $optional_attributes);
430 0         0 my $attributes = $element->attributes;
431 0   0     0 my $children_result = $element->children_result || {};
432 0         0 my $result = $object_constructor->(
433             %$attributes,
434             %$children_result,
435             %$args
436             );
437 0 0       0 $code ? $code->($result) : $result;
438             }
439 0         0 } else {
440             $result = sub {
441 5     5   10 my ($self, $element, $parent) = @_;
442 5         17 my $args = $self->root_args;
443 5 50 33     25 $element->validate_attributes($required_attributes, $optional_attributes)
444             if ($required_attributes || $optional_attributes);
445 5         17 my $attributes = $element->attributes;
446 5   50     17 my $children_result = $element->children_result || {};
447 5         43 my $result = $object_constructor->new(
448             %$attributes,
449             %$children_result,
450             %$args
451             );
452 5 50       45 $code ? $code->($result) : $result;
453             }
454 5         29 }
455 5         33 $result;
456             }
457              
458              
459             =item ignore_node_handler
460              
461             =cut
462              
463             sub ignore_node_handler {
464             sub {
465 1     1   3 my ($self, $element, $parent) = @_;
466 1     1 1 1438 };
467             }
468              
469              
470             =item custom_array_handler
471              
472             Returns handler for transforming roo node to object,
473             Takes hash ref as custom result storage, optionally array ref of the required attributes, hash_ref of the optional attributes,
474             custom storage key to the hash item (by default the element name).
475             This options allows parsing only part of the xml document.
476              
477             my $xml_content = <
478            
479            
480            
481            
482            
483             XML
484              
485              
486             my $result = {};
487             my $xml = Simple::SAX::Serializer->new;
488             $xml->handler('root', ignore_node_handler());
489             $xml->handler('node', custom_array_handler($result, ['name', 'attr1'], {optional_attr1 => undef, attr2 => '2'}, 'my_key'));
490              
491             #or without attributes validation
492             $xml->handler('node', custom_array_handler($result, undef, undef, 'my_key'));
493              
494             $xml->parse_string($xml_content);
495              
496             #transforms $result to ,{ my_key => [
497             {name => 'key1', attr1 => '1', optional_attr1 => undef, attr2 => 2},
498             {name => 'key2', attr1 => '2', optional_attr1 => undef, attr2 => 2}
499             ]
500             };
501              
502             =cut
503              
504             sub custom_array_handler {
505 1     1 1 4 my ($custom_storage, $required_attributes, $optional_attributes, $storage_key) = @_;
506             sub {
507 2     2   3 my ($this, $element, $parent) = @_;
508 2 50 33     13 $element->validate_attributes($required_attributes, $optional_attributes)
509             if ($required_attributes || $optional_attributes);
510 2         7 my $attributes = $element->attributes;
511 2   50     6 my $children_result = $element->children_result || {};
512 2   33     5 my $key = $storage_key || $element->name;
513 2   100     9 my $array = $custom_storage->{$key} ||= [];
514 2         13 push @$array, {%$attributes, %$children_result};
515             }
516 1         9 }
517              
518              
519             =item object_handler
520              
521             Returns handler for transforming node into an object,
522             Takes class name or constructor code reference, optionally array ref of the required attributes, hash_ref of the optional attributes,
523             parent storage key to the hash item (by default the element name).
524              
525             my $xml_content = <
526            
527            
528            
529            
530            
531             XML
532              
533             my $xml = Simple::SAX::Serializer->new;
534              
535             $xml->handler('object1', hash_of_object_array_handler('Object1', ['attr1']));
536             $xml->handler('root', root_object_handler('Root'));
537              
538             my $result = $xml->parse_string($xml_content);
539             #transforms result to
540             Root->new(object1 => [Object1->new(attr1 => 1),Object1->new(attr1 => 2)]);
541              
542             =cut
543              
544             sub object_handler {
545 1     1 1 4 my ($object_constructor, $required_attributes, $optional_attributes, $parent_key) = @_;
546 1         2 my $result;
547 1 50       4 if (ref($object_constructor) eq 'CODE') {
548             $result = sub {
549 0     0   0 my ($self, $element, $parent) = @_;
550 0   0     0 my $children_result = $element->children_result || {};
551 0         0 my $attributes = $element->attributes;
552 0         0 my $result = $parent->children_hash_result;
553 0   0     0 my $key = $parent_key || $element->name;
554 0         0 $result->{$key} = $object_constructor->(%$attributes, %$children_result);
555             }
556 0         0 } else {
557             $result = sub {
558 1     1   3 my ($self, $element, $parent) = @_;
559 1   50     5 my $children_result = $element->children_result || {};
560 1         5 my $attributes = $element->attributes;
561 1         4 my $result = $parent->children_hash_result;
562 1   33     5 my $key = $parent_key || $element->name;
563 1         22 $result->{$key} = $object_constructor->new(%$attributes, %$children_result);
564             }
565 1         6 }
566 1         6 $result;
567             }
568              
569             1;
570              
571              
572             __END__