File Coverage

blib/lib/XML/Struct/Simple.pm
Criterion Covered Total %
statement 51 57 89.4
branch 25 32 78.1
condition 10 12 83.3
subroutine 7 8 87.5
pod 3 3 100.0
total 96 112 85.7


line stmt bran cond sub pod time code
1             package XML::Struct::Simple;
2 1     1   18392 use strict;
  1         2  
  1         35  
3 1     1   480 use Moo;
  1         13893  
  1         8  
4 1     1   1446 use List::Util qw(first);
  1         3  
  1         111  
5 1     1   5 use Scalar::Util qw(reftype blessed);
  1         2  
  1         741  
6              
7             our $VERSION = '0.26';
8              
9             has root => (
10             is => 'rw',
11             default => sub { 0 },
12             );
13              
14             has attributes => (
15             is => 'rw',
16             default => sub { 1 },
17             coerce => sub { !defined $_[0] or ($_[0] and $_[0] ne 'remove') },
18             );
19              
20             has content => (
21             is => 'rw',
22             default => sub { 'content' },
23             );
24              
25             has depth => (
26             is => 'rw',
27             coerce => sub { (defined $_[0] and $_[0] >= 0) ? $_[0] : undef },
28             );
29              
30             sub transform {
31 14     14 1 82 my ($self, $element) = @_;
32            
33 14         29 my $simple = $self->transform_content($element,0);
34              
35             # enforce root for special case text
36 14 100 100     92 if ($self->root or !ref $simple) {
37 7 100       39 my $root = $self->root !~ /^[+-]?[0-9]+$/ ? $self->root : $element->[0];
38 7         52 return { $root => $simple };
39             } else {
40 7         47 return $simple;
41             }
42             }
43              
44             # returns a (possibly empty) hash or a scalar
45             sub transform_content {
46 23     23 1 24 my ($self, $element, $depth) = @_;
47 23 50       45 $depth = 0 if !defined $depth;
48              
49 23 100 100     377 if (defined $self->depth and $depth >= $self->depth) {
    100          
50 3         68 return $element;
51             } elsif ( @$element == 1 ) { # empty tag
52 2         15 return { };
53             }
54              
55 18         580 my $attributes = {};
56 18         18 my $children;
57              
58 18 100       65 if ( reftype $element->[1] eq 'HASH' ) { # [ $tag, \%attributes, \@children ]
59 15 100       205 $attributes = $element->[1] if $self->attributes;
60 15         551 $children = $element->[2];
61             } else { # [ $tag, \@children ]
62 3         3 $children = $element->[1];
63             }
64            
65             # no element children
66 18 100   23   79 unless ( first { ref $_ } @$children ) {
  23         45  
67 9         17 my $content = join "", @$children;
68 9 100       23 if ($content eq '') {
    100          
69 2         6 return { %$attributes };
70             } elsif (!%$attributes) {
71 6         12 return $content;
72             } else {
73 1         7 return { %$attributes, $self->content => $content };
74             }
75             }
76              
77 9         34 my $simple = { map {$_ => [$attributes->{$_}] } keys %$attributes };
  5         20  
78              
79 9         15 foreach my $child ( @$children ) {
80 16 100       29 next unless ref $child; # skip mixed content text
81              
82 9         10 my $name = $child->[0];
83 9         23 my $content = $self->transform_content($child, $depth+1);
84              
85 9 50       23 if ( $simple->{$name} ) {
86 0         0 push @{$simple->{$name}}, $content;
  0         0  
87             } else {
88 9         30 $simple->{$name} = [$content];
89             }
90             }
91              
92 9         21 foreach my $name (keys %$simple) {
93 14 50       13 next if @{$simple->{$name}} != 1;
  14         30  
94 14         18 my $c = $simple->{$name}->[0];
95 14 100 66     52 if (!ref $c or (!blessed $c and reftype $c eq 'HASH')) {
      66        
96 12         21 $simple->{$name} = $c;
97             }
98             }
99              
100 9         18 return $simple;
101             }
102              
103             sub removeXMLAttr {
104 0     0 1   my $node = shift;
105 0           ref $node
106             ? ( $node->[2]
107 0 0         ? [ $node->[0], [ map { removeXMLAttr($_) } @{$node->[2]} ] ]
  0 0          
108             : [ $node->[0] ] ) # empty element
109             : $node; # text node
110             }
111              
112              
113             1;
114             __END__