File Coverage

blib/lib/XML/TinyXML/Node.pm
Criterion Covered Total %
statement 102 139 73.3
branch 34 64 53.1
condition 11 21 52.3
subroutine 22 31 70.9
pod 24 29 82.7
total 193 284 67.9


line stmt bran cond sub pod time code
1             # -*- tab-width: 4 -*-
2             # ex: set tabstop=4:
3              
4             =head1 NAME
5              
6             XML::TinyXML::Node - Tinyxml Node object
7              
8             =head1 SYNOPSIS
9              
10             =over 4
11              
12             use XML::TinyXML;
13              
14             # first obtain an xml context:
15             $xml = XML::TinyXML->new("rootnode", "somevalue", { attr1 => v1, attr2 => v2 });
16              
17             # We create a node and later attach it to a parent one doing:
18             $child_node = XML::TinyXML::Node->new("child", "somevalue");
19             ... [ some code ] ...
20             $parent_node->addChildNode($child_node);
21              
22             # or you can do everything in one go using :
23             $parent_node->addChildNode("child", "somevalue", { attr1 => v1, attr2 => v2 });
24             # the new node will be implicitly created within the addChildNode() method
25              
26             # or you can do the other way round, creating the instance of the new childnode
27             # and passing the parent to the constructor which will take care of calling addChildNode()
28             $child_node = XML::TinyXML::Node->new("child", "somevalue", $attrs, $parent_node);
29              
30             # we can later retrive the "child" node by calling:
31             $child_node = $xml->getNode("/nodelabel/child");
32             # and possibly modify its value by doing:
33             $child_node->value("othervalue");
34              
35             # at this point , calling :
36             print $xml->dump;
37             # would produce the following xml
38             #
39             #
40             #
41             # othervalue
42             #
43              
44             =back
45              
46             =head1 DESCRIPTION
47              
48             Node representation for the TinyXML API
49              
50             =head1 INSTANCE VARIABLES
51              
52             =over 4
53              
54             =item * _node
55              
56             Reference to the underlying XmlNodePtr object (which is a binding to the XmlNode C structure)
57              
58             =back
59              
60             =head1 METHODS
61              
62             =over 4
63              
64             =cut
65             package XML::TinyXML::Node;
66              
67 10     10   50 use strict;
  10         21  
  10         329  
68 10     10   50 use warnings;
  10         21  
  10         24131  
69             our $VERSION = '0.34';
70              
71             =item * new ($entity, $value, $parent, %attrs)
72              
73             Creates a new XML::TinyXML::Node object.
74              
75             $entity can be either a scalar or an XmlNodePtr object.
76             - if it's a scalar , it will be intepreted as the entity name
77             - if it's an XmlNodePtr, it will be used as the underlying object
78             and will be incapsulated in the newly created XML::TinyXML::Node object.
79              
80             $value is the optianal string value of the newly created node (the "content" of
81             the xml node)
82              
83             if $parent isn't undef the newly created node will be directly attached to
84             the specified parent node. $parent can be either a XML::TinyXML::Node object
85             or a XmlNodePtr one.
86              
87             %attrs is an optional hash specifying attributes for the newly created xml node
88              
89             Returns a valid XML::TinyXML::Node object
90              
91             =cut
92             sub new {
93 776     776 1 1234 my ($class, $entity, $value, $attrs, $parent) = @_;
94 776 100       1580 return undef unless($entity);
95 772         895 my $node = undef;
96 772 100 66     3719 if(ref($entity) && UNIVERSAL::isa($entity, "XmlNodePtr")) {
97 747         925 $node = $entity;
98             } else {
99 25 100       50 $value = "" unless defined($value);
100 25         130 $node = XML::TinyXML::XmlCreateNode($entity, $value);
101             }
102 772 50       1492 return undef unless($node);
103 772 50       1438 if(ref($parent)) {
104 0         0 my $pnode = undef;
105 0 0       0 if(UNIVERSAL::isa($parent, "XmlNodePtr")) {
    0          
106 0         0 $pnode = $parent;
107             } elsif(UNIVERSAL::isa($parent, "XML::TinyXML::Node")) {
108 0         0 $pnode = $parent->{_node};
109             }
110 0 0       0 if($pnode) {
111 0         0 XML::TinyXML::XmlAddChildNode($pnode, $node);
112             }
113             }
114 772         1053 my $self = {};
115 772         1789 bless($self, $class);
116 772         1469 $self->{_node} = $node;
117 772 100 66     1741 if($attrs && ref($attrs) eq "HASH") {
118 1         8 $self->addAttributes(%$attrs);
119             }
120 772         3796 $self;
121             }
122              
123             =item * cleanAttributes ()
124              
125             Removes all node attributes
126              
127             =cut
128             sub cleanAttributes {
129 0     0 1 0 my ($self) = @_;
130 0         0 return XML::TinyXML::XmlClearAttributes($self->{_node});
131             }
132              
133             =item * removeAttribute ($index)
134              
135             Removes attribute at $index
136              
137             =cut
138             sub removeAttribute {
139 0     0 1 0 my ($self, $index) = @_;
140 0         0 return XML::TinyXML::XmlRemoveAttribute($self->{_node}, $index);
141             }
142              
143             #=item * removeAttributeByName ($name)
144             #=cut
145              
146             =item * loadHash ($hashref, [ $childname ])
147              
148             Loads an hashref and represent it as an xml subbranch.
149              
150             $hashref
151              
152             if $childname is specified, newly created childnodes will use it as their name
153              
154             =cut
155             sub loadHash {
156 15     15 1 19 my ($self, $hash, $childname, $reset) = @_;
157              
158 15 50       51 $self->removeAllChildren if $reset;
159              
160 15         31 foreach my $k (keys(%$hash)) {
161 22   66     56 my $name = $childname || $k;
162 22 100 66     79 if(!ref($hash->{$k}) || ref($hash->{$k}) eq "SCALAR") {
    100          
    50          
163 14         31 $self->addChildNode(XML::TinyXML::Node->new($name, $hash->{$k}));
164             } elsif(ref($hash->{$k}) eq "HASH") {
165 6         13 my $child = XML::TinyXML::Node->new($name);
166 6         16 $self->addChildNode($child);
167 6         21 $child->loadHash($hash->{$k});
168             } elsif(ref($hash->{$k}) eq "ARRAY") {
169 2         2 foreach my $entry (@{$hash->{$k}}) {
  2         5  
170             #warn "Anonymous/Nested arrayrefs are flattened !!! This should be fixed in the future";
171             #$self->parent->addChildNode($childname);
172 8         26 $self->loadHash({ __import__ => $entry }, $name);
173             }
174             }
175             }
176             }
177              
178             =item * toHash ([ $parent ])
179              
180             Export the xml structure into an hashref (formerly the inverse of loadHash)
181              
182             if $parent is specified the resulting structure will be connected to $parent.
183             (NOTE: $parent MUST obviously be an hashref)
184              
185             =cut
186             sub toHash {
187 7     7 1 23 my ($self, $parent) = @_;
188 7         11 my $hashref = {};
189 7         17 foreach my $child ($self->children) {
190 20         40 my $key = $child->name;
191 20         40 my $value = $child->value;
192 20 100       37 if($child->countChildren) {
193 6         26 $value = $child->toHash($hashref);
194             }
195 20 100       42 if($hashref->{$key}) {
196 6 100       16 if(ref($hashref->{$key}) eq "ARRAY") {
197 5         6 push(@{$hashref->{$key}}, $value);
  5         15  
198             } else {
199 1         4 $hashref->{$key} = [ $hashref->{$key}, $value ];
200             }
201             } else {
202 14         40 $hashref->{$key} = $value;
203             }
204             }
205 7 50 66     37 if($parent && $self->value) {
206 0 0       0 if($parent->{$self->{name}}) {
207 0 0       0 if(ref($parent->{$self->name} eq "ARRAY")) {
208 0         0 push(@{$parent->{$self->name}}, $self->value);
  0         0  
209             } else {
210 0         0 $parent->{$self->name} = [ $parent->{$self->name}, $self->value ];
211             }
212             } else {
213 0         0 $parent->{$self->name} = $self->value;
214             }
215             }
216 7         19 return $hashref;
217             }
218              
219             =item * updateAttributes (%attrs)
220              
221             Updates all attributes.
222              
223             This method simply clean all current attributes and replace them with
224             the ones specified in the %attrs hash
225              
226             =cut
227             sub updateAttributes {
228 0     0 1 0 my ($self, %attrs) = @_;
229 0         0 XML::TinyXML::XmlClearAttributes($self->{_node});
230 0         0 $self->addAttributes(%attrs);
231             }
232              
233             =item * addAttributes (%attrs)
234              
235             Add attributes.
236              
237             =cut
238             sub addAttributes {
239 1     1 1 5 my ($self, %attrs) = @_;
240 1         8 foreach my $key (sort keys %attrs) {
241 2         22 XML::TinyXML::XmlAddAttribute($self->{_node}, $key, $attrs{$key});
242             }
243             }
244              
245             =item * name ([$newname])
246              
247             Set/Get the name of a node.
248             if $newname is specified it will be used as the new name,
249             otherwise the current name is returned
250              
251             =cut
252             sub name {
253 385     385 1 3751 my ($self, $newname) = @_;
254 385 50       781 $self->{_node}->name($newname)
255             if($newname);
256 385         2102 return $self->{_node}->name;
257             }
258              
259             =item * value ([$newval])
260              
261             Set/Get the vlue of a node.
262             if $newval is specified it will be used as the new value,
263             otherwise the current value is returned
264              
265             =cut
266             sub value {
267 41     41 1 123 my ($self, $newval) = @_;
268 41 50       171 $self->{_node}->value($newval)
269             if($newval);
270 41         257 return $self->{_node}->value;
271             }
272              
273             =item * path ()
274              
275             Get the absolute path of a node.
276              
277             =cut
278             sub path {
279 42     42 1 629 my $self = shift;
280 42         223 return $self->{_node}->path;
281             }
282              
283             =item * getAttribute ($index)
284              
285             Returns the attribute (XML::TinyXML::NodeAttribute) at index $index
286              
287             =cut
288             sub getAttribute {
289 0     0 1 0 my ($self, $index) = @_;
290 0         0 my $attr = XML::TinyXML::XmlGetAttribute($self->{_node}, $index);
291 0 0       0 return XML::TinyXML::NodeAttribute->new($attr) if ($attr);
292             }
293              
294             =item * getAttributes ()
295              
296             Returns all attribute (array/arrayref of XML::TinyXML::NodeAttribute objects) for this node
297              
298             =cut
299             sub getAttributes {
300 37     37 1 46 my ($self) = shift;
301 37         42 my @res;
302 37         154 for(my $i = 0; $i < XML::TinyXML::XmlCountAttributes($self->{_node}); $i++) {
303 30         194 push @res, XML::TinyXML::NodeAttribute->new(XML::TinyXML::XmlGetAttribute($self->{_node}, $i));
304             }
305 37 50       139 return wantarray?@res:\@res;
306             }
307              
308             =item * attributes ()
309              
310             Returns an hashref copy of all attributes in this node.
311              
312             The returned hashref must be considered read-only,
313             any change won't be reflected in the underlying document.
314              
315             If you want to modify the name or the value of an attribute,
316             use the XML::TinyXML::NodeAttribute api by calling
317             getAttributes() or getAttribute() instead.
318              
319             =cut
320             sub attributes {
321 6     6 1 40 my ($self) = shift;
322 6         10 my $res = {};
323 6         37 for(my $i = 0; $i < XML::TinyXML::XmlCountAttributes($self->{_node}); $i++) {
324 6         43 my $attr = XML::TinyXML::XmlGetAttribute($self->{_node}, $i);
325 6         83 $res->{$attr->name} = $attr->value;
326             }
327 6         27 return $res;
328             }
329              
330             =item * getChildNode ($index)
331              
332             Returns child node at $index.
333             The returned node will be a Xml::TinyXML::Node object
334              
335             =cut
336             sub getChildNode {
337 6     6 1 3040 my ($self, $index) = @_;
338 6         40 return XML::TinyXML::Node->new(XML::TinyXML::XmlGetChildNode($self->{_node}, $index));
339             }
340              
341             =item * getChildNodeByName ($name)
342              
343             Returns the first child node whose name matches $name.
344             The returned node will be a Xml::TinyXML::Node object
345              
346             =cut
347             sub getChildNodeByName {
348 4     4 1 10 my ($self, $name) = @_;
349 4 50       14 return undef unless($name);
350 4         51 return XML::TinyXML::Node->new(XML::TinyXML::XmlGetChildNodeByName($self->{_node}, $name));
351             }
352              
353             =item * countChildren ()
354              
355             Returns the actual number of children
356              
357             =cut
358             sub countChildren {
359 20     20 1 22 my $self = shift;
360 20         73 return XML::TinyXML::XmlCountChildren($self->{_node});
361             }
362              
363             =item * children ()
364              
365             Returns an array containing all actual children in the form of Xml::TinyXML::Node objects
366              
367             =cut
368             sub children {
369 387     387 1 483 my ($self) = @_;
370 387         441 my @children;
371 387         1509 for (my $i = 0; $i < XML::TinyXML::XmlCountChildren($self->{_node}); $i++) {
372 528         2356 push (@children, XML::TinyXML::Node->new(XML::TinyXML::XmlGetChildNode($self->{_node}, $i)));
373             }
374 387 50       1556 return wantarray?@children:\@children;
375             }
376              
377             =item * addChildNode ($child [, $value [, $attrs ] ])
378              
379             Adds a new child node.
380              
381             If $child is an XML::TinyXML::Node object , this will be attached to our children list
382              
383             If $child is a string (not a reference) a new node will be created passing $child and the
384             optional $value and $attrs arguments to the constructor and than attached to the children list
385              
386             =cut
387             sub addChildNode {
388 22     22 1 28 my ($self, $child, $value, $attrs) = @_;
389 22 50 33     105 if ($child && UNIVERSAL::isa($child, "XML::TinyXML::Node")) {
    0 0        
390 22         150 return XML::TinyXML::XmlAddChildNode($self->{_node}, $child->{_node});
391             } elsif ($child and !ref($child)) {
392 0         0 my $node = XML::TinyXML::Node->new($child, $value, $attrs, $self);
393 0 0       0 if ($node) {
394 0         0 return $self->addChildNode($node);
395             }
396             }
397             }
398              
399             =item * removeChildNode ($index)
400              
401             Removes child node at provided $index.
402              
403             =cut
404             sub removeChildNode {
405 0     0 1 0 my ($self, $index) = @_;
406 0         0 XML::TinyXML::XmlRemoveChildNode($self->{_node}, $index);
407             }
408              
409             =item * removeAllChildren
410              
411             Removes all children from this node
412              
413             =cut
414             sub removeAllChildren {
415 0     0 1 0 my ($self) = @_;
416 0         0 for (my $i = 0; $i < $self->countChildren; $i++) {
417 0         0 XML::TinyXML::XmlRemoveChildNode($self->{_node}, $i);
418             }
419             }
420              
421             =item * parent ()
422              
423             Read-Only method which returns the parent node in the form of a XML::TinyXML::Node object.
424              
425             =cut
426             sub parent {
427 18     18 1 24 my ($self) = @_;
428 18         90 return XML::TinyXML::Node->new($self->{_node}->parent);
429             }
430              
431             =item * nextSibling ()
432              
433             Returns the next sibling of this node (if any),
434             undef otherwise.
435              
436             =cut
437             sub nextSibling {
438 5     5 1 6 my ($self) = @_;
439 5         21 return XML::TinyXML::Node->new(XML::TinyXML::XmlNextSibling($self->{_node}));
440             }
441              
442             =item * prevSibling ()
443              
444             Returns the previous sibling of this node (if any),
445             undef otherwise.
446              
447             =cut
448             sub prevSibling {
449 4     4 1 5 my ($self) = @_;
450 4         23 return XML::TinyXML::Node->new(XML::TinyXML::XmlPrevSibling($self->{_node}));
451             }
452              
453             sub namespace {
454 15     15 0 56 my ($self) = @_;
455 15         129 return XML::TinyXML::XmlGetNodeNamespace($self->{_node});
456             }
457              
458             sub knownNamespaces {
459 0     0 0 0 my ($self) = @_;
460             return wantarray
461 0 0       0 ? @{$self->{_node}->knownNamespaces}
  0         0  
462             : $self->{_node}->knownNamespaces;
463             }
464              
465             sub myNamespace {
466 0     0 0 0 my ($self) = @_;
467 0         0 return $self->{_node}->ns;
468             }
469              
470             sub hineritedNamespace {
471 3     3 0 9 my ($self) = @_;
472 3         26 return $self->{_node}->hns;
473             }
474              
475             sub defaultNamespace {
476 0     0 0 0 my ($self) = @_;
477 0         0 return $self->{_node}->cns;
478             }
479              
480             =item * type ()
481              
482             Returns the "type" of a XML::TinyXML::Node object.
483             type can be :
484             NODE
485             COMMENT
486             CDATA
487              
488             =cut
489             sub type {
490 161     161 1 208 my ($self) = @_;
491 161         485 my $type = $self->{_node}->type;
492 161 100       386 if($type == XML::TinyXML::XML_NODETYPE_SIMPLE()) {
    100          
    50          
493 137         183 $type = "NODE";
494             } elsif ($type == XML::TinyXML::XML_NODETYPE_COMMENT()) {
495 12         17 $type = "COMMENT";
496             } elsif ($type == XML::TinyXML::XML_NODETYPE_CDATA()) {
497 12         20 $type = "CDATA";
498             }
499 161         549 return $type;
500             }
501              
502             1;
503              
504             =back
505              
506             =head1 SEE ALSO
507              
508             =over 4
509              
510             XML::TinyXML
511              
512             =back
513              
514             =head1 AUTHOR
515              
516             xant, Exant@cpan.orgE
517              
518             =head1 COPYRIGHT AND LICENSE
519              
520             Copyright (C) 2008-2010 by xant
521              
522             This library is free software; you can redistribute it and/or modify
523             it under the same terms as Perl itself, either Perl version 5.8.8 or,
524             at your option, any later version of Perl 5 you may have available.
525              
526              
527             =cut