File Coverage

blib/lib/XML/Struct/Simple.pm
Criterion Covered Total %
statement 50 57 87.7
branch 24 32 75.0
condition 9 12 75.0
subroutine 7 8 87.5
pod 3 3 100.0
total 93 112 83.0


line stmt bran cond sub pod time code
1             package XML::Struct::Simple;
2 1     1   25435 use strict;
  1         3  
  1         51  
3 1     1   2357 use Moo;
  1         18494  
  1         7  
4 1     1   1882 use List::Util qw(first);
  1         2  
  1         154  
5 1     1   6 use Scalar::Util qw(reftype blessed);
  1         3  
  1         991  
6              
7             our $VERSION = '0.25';
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 11     11 1 109 my ($self, $element) = @_;
32            
33 11         28 my $simple = $self->transform_content($element,0);
34              
35             # enforce root for special case text
36 11 100 100     94 if ($self->root or !ref $simple) {
37 6 100       52 my $root = $self->root !~ /^[+-]?[0-9]+$/ ? $self->root : $element->[0];
38 6         62 return { $root => $simple };
39             } else {
40 5         52 return $simple;
41             }
42             }
43              
44             # returns a (possibly empty) hash or a scalar
45             sub transform_content {
46 18     18 1 28 my ($self, $element, $depth) = @_;
47 18 50       53 $depth = 0 if !defined $depth;
48              
49 18 100 100     457 if (defined $self->depth and $depth >= $self->depth) {
    50          
50 3         110 return $element;
51             } elsif ( @$element == 1 ) { # empty tag
52 0         0 return { };
53             }
54              
55 15         942 my $attributes = {};
56 15         17 my $children;
57              
58 15 100       78 if ( reftype $element->[1] eq 'HASH' ) { # [ $tag, \%attributes, \@children ]
59 14 100       336 $attributes = $element->[1] if $self->attributes;
60 14         837 $children = $element->[2];
61             } else { # [ $tag, \@children ]
62 1         3 $children = $element->[1];
63             }
64            
65             # no element children
66 15 100   21   104 unless ( first { ref $_ } @$children ) {
  21         53  
67 8         23 my $content = join "", @$children;
68 8 100       21 if (!%$attributes) {
    100          
69 6         23 return $content;
70             } elsif ($content eq '') {
71 1         8 return { %$attributes };
72             } else {
73 1         10 return { %$attributes, $self->content => $content };
74             }
75             }
76              
77 7         41 my $simple = { map {$_ => [$attributes->{$_}] } keys %$attributes };
  5         28  
78              
79 7         15 foreach my $child ( @$children ) {
80 14 100       37 next unless ref $child; # skip mixed content text
81              
82 7         13 my $name = $child->[0];
83 7         30 my $content = $self->transform_content($child, $depth+1);
84              
85 7 50       27 if ( $simple->{$name} ) {
86 0         0 push @{$simple->{$name}}, $content;
  0         0  
87             } else {
88 7         34 $simple->{$name} = [$content];
89             }
90             }
91              
92 7         28 foreach my $name (keys %$simple) {
93 12 50       14 next if @{$simple->{$name}} != 1;
  12         33  
94 12         23 my $c = $simple->{$name}->[0];
95 12 100 33     69 if (!ref $c or (!blessed $c and reftype $c eq 'HASH')) {
      66        
96 10         31 $simple->{$name} = $c;
97             }
98             }
99              
100 7         21 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__