File Coverage

blib/lib/XML/MyXML/Object.pm
Criterion Covered Total %
statement 144 159 90.5
branch 65 80 81.2
condition 19 22 86.3
subroutine 17 18 94.4
pod 0 12 0.0
total 245 291 84.1


line stmt bran cond sub pod time code
1             package XML::MyXML::Object;
2              
3 2     2   14 use strict;
  2         4  
  2         56  
4 2     2   10 use warnings;
  2         4  
  2         46  
5              
6 2     2   608 use Encode;
  2         10894  
  2         184  
7 2     2   16 use Carp;
  2         3  
  2         115  
8 2     2   12 use Scalar::Util qw/ weaken /;
  2         5  
  2         3826  
9              
10             our $VERSION = "1.07";
11              
12             sub new {
13 0     0 0 0 my $class = shift;
14 0         0 my $xml = shift;
15              
16 0         0 my $obj = XML::MyXML::xml_to_object($xml);
17 0         0 bless $obj, $class;
18 0         0 return $obj;
19             }
20              
21             sub _parse_description {
22 40     40   77 my ($desc) = @_;
23              
24 40         206 my ($tag, $attrs_str) = $desc =~ /\A([^\[]*)(.*)\z/g;
25 40         113 my %attrs = $attrs_str =~ /\[([^\]=]+)(?:=(\"[^"]*\"|[^"\]]*))?\]/g;
26 40         109 foreach my $value (values %attrs) {
27 5         12 $value =~ s/\A\"//;
28 5         14 $value =~ s/\"\z//;
29             }
30              
31 40         109 return ($tag, \%attrs);
32             }
33              
34             sub cmp_element {
35 83     83 0 154 my ($self, $desc) = @_;
36              
37             my ($tag, $attrs) = ref $desc
38 83 100       196 ? @$desc{qw/ tag attrs /}
39             : _parse_description($desc);
40              
41 83 100 100     934 ! length $tag or $self->{element} =~ /(\A|\:)\Q$tag\E\z/ or return 0;
42 51         140 foreach my $attr (keys %$attrs) {
43 14         31 my $val = $self->attr($attr);
44 14 50       30 defined $val or return 0;
45 14 100 66     63 ! defined $attrs->{$attr} or $attrs->{$attr} eq $val or return 0;
46             }
47              
48 44         134 return 1;
49             }
50              
51             sub children {
52 33     33 0 46 my $self = shift;
53 33         59 my $tag = shift;
54              
55 33 50       71 $tag = '' if ! defined $tag;
56              
57 33         52 my @all_children = grep { defined $_->{element} } @{$self->{content}};
  138         277  
  33         73  
58 33 50       87 length $tag or return @all_children;
59              
60 33         72 ($tag, my $attrs) = _parse_description($tag);
61 33         98 my $desc = { tag => $tag, attrs => $attrs };
62              
63 33         90 my @results = grep $_->cmp_element($desc), @all_children;
64              
65 33         182 return @results;
66             }
67              
68             sub path {
69 27     27 0 7875 my $self = shift;
70 27         52 my $path = shift;
71              
72 27         45 my @path;
73 27         48 my $orig_path = $path;
74 27         82 my $start_root = $path =~ m!\A/!;
75 27 100       94 $path = "/" . $path unless $start_root;
76 27         83 while (length $path) {
77 37         218 my $success = $path =~ s!\A/((?:[^/\[]*)?(?:\[[^\]=]+(?:=(?:\"[^"]*\"|[^"\]]*))?\])*)!!;
78 37         118 my $seg = $1;
79 37 50       82 if ($success) {
80 37         108 push @path, $seg;
81             } else {
82 0         0 croak "Invalid XML path: $orig_path";
83             }
84             }
85              
86 27         58 my @result = ($self);
87 27 100       55 if ($start_root) {
88 7 100       20 $self->cmp_element(shift @path) or return;
89             }
90 26         74 for (my $i = 0; $i <= $#path; $i++) {
91 29         104 @result = map $_->children( $path[$i] ), @result;
92 29 50       151 @result or return;
93             }
94 26 100       143 return wantarray ? @result : $result[0];
95             }
96              
97             sub text {
98 33     33 0 55 my $self = shift;
99 33 100 100     111 my $flags = (@_ and ref $_[-1]) ? pop() : {};
100 33 100       61 my $set_value = @_ ? defined $_[0] ? shift() : '' : undef;
    100          
101              
102 33 100       61 if (! defined $set_value) {
103 30         40 my $value = '';
104 30 100       64 if ($self->{content}) {
105 15         19 foreach my $child (@{ $self->{content} }) {
  15         29  
106 18         42 $value .= $child->value($flags);
107             }
108             }
109 30 100       73 if ($self->{value}) {
110 12         25 my $temp_value = $self->{value};
111 12 100       24 if ($flags->{strip}) { $temp_value = XML::MyXML::_strip($temp_value); }
  2         7  
112 12         30 $value .= $temp_value;
113             }
114 30         95 return $value;
115             } else {
116 3 100       9 if (length $set_value) {
117 1         4 my $entry = { value => $set_value, parent => $self };
118 1         6 weaken( $entry->{parent} );
119 1         3 bless $entry, 'XML::MyXML::Object';
120 1         7 $self->{content} = [ $entry ];
121             } else {
122 2         9 $self->{content} = [];
123             }
124             }
125             }
126              
127             *value = \&text;
128              
129             sub inner_xml {
130 6     6 0 25 my $self = shift;
131 6 100 100     29 my $flags = (@_ and ref $_[-1]) ? pop() : {};
132 6 100       19 my $set_xml = @_ ? defined $_[0] ? shift() : '' : undef;
    100          
133              
134 6 100       15 if (! defined $set_xml) {
135 3         8 my $xml = $self->to_xml($flags);
136 3         19 $xml =~ s/\A\<.*?\>//s;
137 3         31 $xml =~ s/\<\/[^\>]*\>\z//s;
138 3         19 return $xml;
139             } else {
140 3         9 my $xml = "
$set_xml
";
141 3         9 my $obj = XML::MyXML::xml_to_object($xml, $flags);
142 3         16 $self->{content} = [];
143 3 100       19 foreach my $child (@{ $obj->{content} || [] }) {
  3         17  
144 4         9 $child->{parent} = $self;
145 4         11 weaken( $child->{parent} );
146 4         6 push @{ $self->{content} }, $child;
  4         13  
147             }
148             }
149             }
150              
151             sub attr {
152 30     30 0 66 my $self = shift;
153 30         85 my $attrname = shift;
154 30         55 my ($set_to, $must_set, $flags);
155 30 100       67 if (@_) {
156 2         5 my $next = shift;
157 2 50       5 if (! ref $next) {
158 2         5 $set_to = $next;
159 2         3 $must_set = 1;
160 2         5 $flags = shift;
161             } else {
162 0         0 $flags = $next;
163             }
164             }
165 30   50     121 $flags ||= {};
166              
167 30 50       56 if (defined $attrname) {
168 30 100       53 if ($must_set) {
169 2 100       4 if (defined ($set_to)) {
170 1         3 $self->{attrs}{$attrname} = $set_to;
171 1         3 return $set_to;
172             } else {
173 1         4 delete $self->{attrs}{$attrname};
174 1         4 return;
175             }
176             } else {
177 28         58 my $attrvalue = $self->{attrs}->{$attrname};
178 28         132 return $attrvalue;
179             }
180             } else {
181 0         0 return %{$self->{attrs}};
  0         0  
182             }
183             }
184              
185             sub tag {
186 5     5 0 15 my $self = shift;
187 5   100     21 my $flags = shift || {};
188              
189 5         10 my $tag = $self->{element};
190 5 50       13 if (defined $tag) {
191 5 100       21 $tag =~ s/\A.*\:// if $flags->{strip_ns};
192 5         39 return $tag;
193             } else {
194 0         0 return undef;
195             }
196             }
197              
198             sub parent {
199 2     2 0 5 my $self = shift;
200              
201 2         10 return $self->{parent};
202             }
203              
204             sub simplify {
205 14     14 0 26 my $self = shift;
206 14   100     43 my $flags = shift || {};
207              
208 14         54 my $simple = XML::MyXML::_objectarray_to_simple([$self], $flags);
209 14 100       43 if (! $flags->{internal}) {
210 9         29 return $simple;
211             } else {
212 5 50       16 if (ref $simple eq 'HASH') {
    0          
213 5         30 return (values %$simple)[0];
214             } elsif (ref $simple eq 'ARRAY') {
215 0         0 return $simple->[1];
216             }
217             }
218             }
219              
220             sub to_xml {
221 21     21 0 1184 my $self = shift;
222 21   100     73 my $flags = shift || {};
223              
224 21 50       54 my $decl = $flags->{complete} ? ''."\n" : '';
225 21         79 my $xml = XML::MyXML::_objectarray_to_xml([$self]);
226 21 100       62 if ($flags->{tidy}) { $xml = XML::MyXML::tidy_xml($xml, { %$flags, bytes => 0, complete => 0, save => undef }); }
  3         22  
227 21         50 $xml = $decl . $xml;
228 21 50       54 if (defined $flags->{save}) {
229 0 0       0 open my $fh, '>', $flags->{save} or croak "Error: Couldn't open file '$flags->{save}' for writing: $!";
230 0         0 binmode $fh, ':encoding(UTF-8)';
231 0         0 print $fh $xml;
232 0         0 close $fh;
233             }
234 21 100       62 $xml = encode_utf8($xml) if $flags->{bytes};
235 21         112 return $xml;
236             }
237              
238             sub to_tidy_xml {
239 1     1 0 577 my $self = shift;
240 1   50     5 my $flags = shift || {};
241              
242 1         8 return $self->to_xml({ %$flags, tidy => 1 });
243             }
244              
245             1;