File Coverage

blib/lib/XML/DOM2/DOM/Element.pm
Criterion Covered Total %
statement 136 306 44.4
branch 49 168 29.1
condition 11 26 42.3
subroutine 25 52 48.0
pod 48 48 100.0
total 269 600 44.8


line stmt bran cond sub pod time code
1             package XML::DOM2::DOM::Element;
2              
3             =head1 NAME
4              
5             XML::DOM2::DOM::Element - A library of DOM (Document Object Model) methods for XML Elements.
6              
7             =head1 DESCRIPTION
8              
9             Provides all the DOM method for XML Elements
10              
11             =head1 METHODS
12              
13             =cut
14              
15 3     3   35 use base "XML::DOM2::DOM::NameSpace";
  3         6  
  3         236  
16              
17 3     3   17 use strict;
  3         6  
  3         84  
18 3     3   16 use Carp;
  3         6  
  3         14387  
19              
20             =head2 $element->getFirstChild()
21              
22             =head2 $element->firstChild()
23              
24             Returns the elements first child in it's children list
25              
26             =cut
27             sub getFirstChild ($) {
28 1     1 1 3 my $self=shift;
29              
30 1 50       4 if (my @children=$self->getChildren) {
31 1         4 return $children[0];
32             }
33 0         0 return undef;
34             }
35             *firstChild=\&getFirstChild;
36              
37             =head2 $element->getLastChild()
38              
39             =head2 $element->lastChild()
40              
41             Returns the elements last child in it's children list
42              
43             =cut
44             sub getLastChild ($) {
45 0     0 1 0 my $self=shift;
46              
47 0 0       0 if (my @children=$self->getChildren) {
48 0         0 return $children[-1];
49             }
50              
51 0         0 return undef;
52             }
53             *lastChild=\&getLastChild;
54              
55             =head2 $element->getChildIndex( @children )
56              
57             Return the array index of this element in the parent or the passed list (if there is one).
58              
59             =cut
60             sub getChildIndex ($;@) {
61 1     1 1 3 my ($self,@children)=@_;
62              
63 1 50       6 unless (@children) {
64 0         0 my $parent=$self->getParent();
65 0         0 @children=$parent->getChildren();
66 0 0       0 return undef unless @children;
67             }
68              
69 1         4 for my $index (0..$#children) {
70 1 50       6 return $index if $children[$index] == $self;
71             }
72              
73 0         0 return undef;
74             }
75              
76             =head2 $element->getChildAtIndex( $index )
77              
78             Return the element at the specified index (the index can be negative).
79              
80             =cut
81             sub getChildAtIndex ($$;@) {
82 0     0 1 0 my ($self,$index,@children)=@_;
83              
84 0 0       0 unless (@children) {
85 0         0 my $parent=$self->getParent();
86 0         0 @children=$parent->getChildren();
87 0 0       0 return undef unless @children;
88             }
89              
90 0         0 return $children[$index];
91             }
92              
93             =head2 $element->getNextSibling()
94              
95             =head2 $element->nextSibling()
96              
97             Return the next element to this element in the parents child list.
98              
99             =cut
100             sub getNextSibling ($) {
101 1     1 1 3 my $self=shift;
102              
103 1 50       4 if (my $parent=$self->getParent) {
104 1         4 my @children=$parent->getChildren();
105 1         10 my $index=$self->getChildIndex(@children);
106 1 50 33     11 if (defined $index and scalar(@children)>$index) {
107 1         5 return $children[$index+1];
108             }
109             }
110 0         0 return undef;
111             }
112             *nextSibling=\&getNextSibling;
113              
114             =head2 $element->getPreviousSibling()
115              
116             =head2 $element->previousSibling()
117              
118             Return the previous element to this element in the parents child list.
119              
120             =cut
121             sub getPreviousSibling ($) {
122 0     0 1 0 my $self=shift;
123              
124 0 0       0 if (my $parent=$self->getParent) {
125 0         0 my @children=$parent->getChildren();
126 0         0 my $index=$self->getChildIndex(@children);
127 0 0       0 if ($index) {
128 0         0 return $children[$index-1];
129             }
130             }
131              
132 0         0 return undef;
133             }
134             *previousSibling=\&getPreviousSibling;
135              
136             =head2 $element->getChildren()
137              
138             =head2 $element->getChildElements()
139              
140             =head2 $element->getChildNodes()
141              
142             Returns all the elements children.
143              
144             =cut
145             sub getChildren ($) {
146 24     24 1 33 my $self=shift;
147 24 100       66 if ($self->{'children'}) {
148 16         19 return @{$self->{'children'}};
  16         73  
149             }
150 8         65 return ();
151             }
152             *getChildElements=\&getChildren;
153             *getChildNodes=\&getChildren;
154              
155             =head2 $element->getChildrenByName( $name )
156              
157             Returns all the elements children with that tag name (including namespace prefix).
158              
159             =cut
160             sub getChildrenByName
161             {
162 0     0 1 0 my ($self, $name) = @_;
163 0 0       0 if(defined($self->{'child'}->{$name})) {
164 0 0       0 if(wantarray) {
165 0         0 return @{$self->{'child'}->{$name}};
  0         0  
166             } else {
167 0         0 return $self->{'child'}->{$name}->[0];
168             }
169             }
170             }
171              
172             =head2 $element->hasChildren()
173              
174             =head2 $element->hasChildElements()
175              
176             =head2 $element->hasChildNodes()
177              
178             Returns 1 if this element has children.
179              
180             =cut
181             sub hasChildren ($) {
182 39     39 1 53 my $self=shift;
183              
184 39 100       109 if (exists $self->{'children'}) {
185 8 50       9 if (scalar @{$self->{'children'}}) {
  8         26  
186 8         44 return 1;
187             }
188             }
189              
190 31         124 return 0;
191             }
192             *hasChildElements=\&hasChildren;
193             *hasChildNodes=\&hasChildren;
194              
195             =head2 $element->getParent()
196              
197             =head2 $element->getParentElement()
198              
199             =head2 $element->getParentNode()
200              
201             Returns the object of the parent element.
202              
203             =cut
204             sub getParent ($) {
205 85     85 1 174 my $self=shift;
206              
207 85 100       287 if ($self->{'parent'}) {
208 49         201 return $self->{'parent'};
209             }
210              
211 36         139 return undef;
212             }
213             *getParentElement=\&getParent;
214             *getParentNode=\&getParent;
215              
216             =head2 $element->setParent( $element )
217              
218             =head2 $element->setParentElement( $element )
219              
220             $element->setParent($parent);
221              
222             Sets the parent node, used internaly.
223              
224             =cut
225             sub setParent ($$) {
226 18     18 1 27 my ($self,$parent) = @_;
227              
228 18 50 33     53 if(ref($parent) or not defined($parent)) {
229 18         34 $self->{'parent'} = $parent;
230 18         31 return 1;
231             }
232              
233 0         0 return undef;
234             }
235             *setParentElement=\&setParent;
236              
237             =head2 $element->getParents()
238              
239             =head2 $element->getParentElements()
240              
241             =head2 $element->getParentNodes()
242              
243             =head2 $element->getAncestors()
244              
245             Return a list of the parents of the current element, starting from the immediate parent. The
246             last member of the list should be the document element.
247              
248             =cut
249             sub getParents {
250 0     0 1 0 my $self=shift;
251              
252 0         0 my $parent = $self->getParent;
253 0 0       0 return undef unless $parent;
254              
255 0         0 my @parents;
256 0         0 while ($parent) {
257 0         0 push @parents,$parent;
258 0         0 $parent=$parent->getParent;
259             }
260              
261 0         0 return @parents;
262             }
263             *getParentElements=\&getParents;
264             *getParentNodes=\&getParents;
265             *getAncestors=\&getParents;
266              
267             =head2 $element->isAncestor( $node )
268              
269             Returns true if the current element is an ancestor of the descendant element.
270              
271             =cut
272             sub isAncestor ($$) {
273 0     0 1 0 my ($self,$descendant)=@_;
274              
275 0         0 my @parents=$descendant->getParents();
276 0         0 foreach my $parent (@parents) {
277 0 0       0 return 1 if $parent==$self;
278             }
279              
280 0         0 return 0;
281             }
282              
283             =head2 $element->isDescendant( $node )
284              
285             Return true if the crrent element is the descendant of the ancestor element.
286              
287             =cut
288             sub isDescendant ($$) {
289 0     0 1 0 my ($self,$ancestor)=@_;
290              
291 0         0 my @parents=$self->getParents();
292 0         0 foreach my $parent (@parents) {
293 0 0       0 return 1 if $parent==$ancestor;
294             }
295              
296 0         0 return 0;
297             }
298              
299             =head2 $element->getSiblings()
300              
301             Returns a list of sibling elements.
302              
303             =cut
304             sub getSiblings ($) {
305 0     0 1 0 my $self=shift;
306              
307 0 0       0 if (my $parent=$self->getParent) {
308 0         0 return $parent->getChildren();
309             }
310              
311 0 0       0 return wantarray?():undef;
312             }
313              
314             =head2 $element->hasSiblings()
315              
316             Returns true if the elements has sibling elements.
317              
318             =cut
319             sub hasSiblings ($) {
320 0     0 1 0 my $self=shift;
321              
322 0 0       0 if (my $parent=$self->getParent) {
323 0         0 my $siblings=scalar($parent->getChildren);
324 0 0       0 return 1 if $siblings>=2;
325             }
326              
327 0         0 return undef;
328             }
329              
330             =head2 $element->getElementName()
331              
332             =head2 $element->getElementType()
333              
334             =head2 $element->getType()
335              
336             =head2 $element->getTagName()
337              
338             =head2 $element->getTagType()
339              
340             =head2 $element->getNodeName()
341              
342             =head2 $element->getNodeType()
343              
344             Return a string containing the name (i.e. the type, not the Id) of an element.
345              
346             =cut
347             sub getElementName ($) {
348 0     0 1 0 my $self=shift;
349              
350 0         0 return $self->name;
351             }
352             *getType=\&getElementName;
353             *getElementType=\&getElementName;
354             *getTagName=\&getElementName;
355             *getTagType=\&getElementName;
356             *getNodeName=\&getElementName;
357             *getNodeType=\&getElementName;
358              
359             =head2 $element->getElementId()
360              
361             Return a string containing the elements Id (unique identifier string).
362              
363             =cut
364             sub getElementId ($) {
365 18     18 1 26 my $self=shift;
366              
367 18 50       46 if (exists $self->{id}) {
368 0         0 return $self->{id};
369             }
370              
371 18         29 return undef;
372             }
373              
374             =head2 $element->getAttribute( $attributeName )
375              
376             Returns the specified attribute in the element, will return a
377             serialised string instead of posible attribute object if serialise set.
378              
379             =cut
380             sub getAttribute
381             {
382 10     10 1 19 my ($self, $name) = @_;
383 10         118 my $attribute = $self->{'attributes'}->{''}->{$name};
384 10         26 return $attribute;
385             }
386              
387             =head2 $element->getAttributes( $serialise, $ns )
388              
389             Returns a list of attributes in various forms.
390              
391             =cut
392             sub getAttributes
393             {
394 3     3 1 6 my ($self, $serialise, $ns) = @_;
395 3         20 my @names = $self->getAttributeNamesNS($ns);
396 3         6 my %attributes;
397             my @attributes;
398 3         6 foreach my $nsr (@names) {
399 3         4 my ($sns, $name) = @{$nsr};
  3         7  
400 3         4 my $attribute;
401 3 50       7 if($sns) {
402 0         0 $attribute = $self->getAttributeNS($sns, $name, $serialise);
403             } else {
404 3         9 $attribute = $self->getAttribute($name, $serialise);
405             }
406 3 50       10 if(not defined($attribute)) {
407 0         0 die "Something is very wrong with the attributes";
408             }
409 3 50       8 if(not ref($attribute)) {
410 0         0 die "An attribute should always be an object: ($name:$attribute) ".$self->name."\n";
411             }
412 3 50       7 if($serialise <= 1) {
413 0         0 $attributes{$attribute->name} = $attribute;
414             } else {
415 3         13 push @attributes, $attribute->serialise_full;
416             }
417             }
418 3 50       11 if($serialise <= 1) {
    50          
419 0 0       0 return wantarray ? %attributes : \%attributes;
420             } elsif($serialise == 2) {
421 0 0       0 return wantarray ? @attributes : \@attributes;
422             } else {
423 3         20 return join(' ', @attributes);
424             }
425             }
426              
427             =head2 $element->getAttributeNames()
428              
429             Returns a list of attribute names, used internaly.
430              
431             =cut
432             sub getAttributeNames
433             {
434 3     3 1 5 my ($self, $ns) = @_;
435 3 50       9 my $prefix = $ns ? $ns->ns_prefix : '';
436 3 50       9 warn "The prefix is undefined!" if not defined($prefix);
437 3         11 my @names;
438 3         5 foreach my $name (keys(%{$self->{'attributes'}->{$prefix}})) {
  3         12  
439 3         11 push @names, $name;
440             }
441 3 50       17 return wantarray ? @names : \@names;
442             }
443              
444             =head2 $element->getAttributeNamesNS( $namespace )
445              
446             Returns a list of attribute names, used internaly.
447              
448             =cut
449             sub getAttributeNamesNS
450             {
451 3     3 1 5 my ($self, $ns) = @_;
452             # Default Namespace
453 3         4 my @names;
454              
455             # Get all other name spaces
456 3 50       16 my @ns = $ns ? ($ns) : $self->getAttributeNamespaces;
457              
458 3         7 foreach my $sns (@ns) {
459 3 50       13 if(defined($sns)) {
460 3         12 foreach my $name ($self->getAttributeNames($sns)) {
461 3         15 push @names, [ $sns, $name ];
462             }
463             } else {
464 0         0 warn "One of the name spaces is not defined\n";
465             }
466             }
467 3         9 return @names;
468             }
469              
470             =head2 $element->getAttributeNamespaces()
471              
472             Returns a list of attribute names, used internaly.
473              
474             =cut
475             sub getAttributeNamespaces
476             {
477 3     3 1 5 my ($self) = @_;
478 3 50       4 return map { $_ ne '' ? $self->document->getNamespace($_) : '' } keys(%{$self->{'attributes'}});
  3         24  
  3         8  
479             }
480              
481             =head2 $element->hasAttribute( $attributeName )
482              
483             Returns true if this element as this attribute.
484              
485             =cut
486             sub hasAttribute
487             {
488 0     0 1 0 my ($self, $name) = @_;
489 0 0       0 return 1 if exists( $self->{'attributes'}->{''}->{$name} );
490             }
491              
492             =head2 $element->hasAttributeNS( $namespace, $attributeName )
493              
494             Returns true if this attribute in this namespace is in this element.
495              
496             =cut
497             sub hasAttributeNS
498             {
499 0     0 1 0 my ($self, $ns, $name) = @_;
500 0         0 my $prefix = $ns->ns_prefix;
501 0 0       0 return 1 if exists( $self->{'attributes'}->{$prefix}->{$name} );
502             }
503              
504             =head2 $element->hasAttributes()
505              
506             Return true is element has any attributes
507              
508             =cut
509              
510             sub hasAttributes
511             {
512 10     10 1 15 my ($self) = @_;
513 10 100 66     46 return 1 if $self->{'attributes'} and keys(%{ $self->{'attributes'} })
  3         28  
514             }
515              
516             =head2 $element->setAttribute( $attribute, $value )
517              
518             Set an attribute on this element, it will accept serialised strings or objects.
519              
520             =cut
521             sub setAttribute
522             {
523 6     6 1 14 my ($self, $name, $value) = @_;
524 6 50       15 confess "Name is not defined" if not $name;
525 6         23 my $existing = $self->getAttribute($name);
526             # This ensures that ids are updated in a sane way.
527 6 50 66     33 if ($name eq "id" and $self->document and defined($value)) {
      66        
528             # Set the new id
529 2 50       10 if($self->document->addId($value, $self)) {
530 2 50       14 if($existing) {
531             # Remove the old id
532 0         0 my $oldvalue = $existing->serialise;
533 0         0 $self->document->removeId($oldvalue);
534             }
535             } else {
536 0         0 $self->error('setAttribute', "Id '$value' already exists in document, unable to modify attribute");
537 0         0 return undef;
538             }
539             }
540              
541             # Some elements can't contain attributes
542 6         26 $self->{'attributes'}->{''}->{$name} = $self->_get_attribute_object( $name, $value, undef, $existing );
543 6         25 return 1;
544             }
545              
546             sub _get_attribute_object
547             {
548 6     6   14 my ($self, $name, $value, $ns, $existing) = @_;
549 6 50       21 if(not $self->_can_contain_attributes) {
550 0         0 $self->error('setAttribute', "This Element can not contain attributes. (".$self->getElementName.")");
551 0         0 return undef;
552             }
553             # undef means delete attribute
554 6 50       90 return $self->removeAttribute($name) if not defined($value);
555 6         8 my $result;
556             # This is to handle attributes handled by objects
557 6 50       21 if($self->_has_attribute($name)) {
558 6         9 $result = $existing;
559 6 50       14 if(not $result) {
560             # Create a new attribute
561 6         57 $result = $self->_attribute_handle( $name, name => $name, namespace => $ns, owner => $self );
562            
563             }
564 6 50       21 croak "Unable to setAttribute, _attribute_handle does not exist (".ref($self).":$name)" if not ref($result);
565 6         38 $result->deserialise($value);
566             }
567 6         27 return $result;
568             }
569              
570             =head2 $element->removeAttribute( $name )
571              
572             Remove a single attribute from this element.
573              
574             =cut
575             sub removeAttribute
576             {
577 0     0 1 0 my ($self, $name) = @_;
578 0 0       0 if($self->hasAttribute($name)) {
579 0         0 my $attribute = delete($self->{'attributes'}->{''}->{$name});
580 0         0 $attribute->delete;
581             }
582             }
583              
584             =head2 $element->removeAttributeNS( $namespace, $name )
585              
586             Remove a single attribute from this element.
587              
588             =cut
589             sub removeAttributeNS
590             {
591 0     0 1 0 my ($self, $ns, $name) = @_;
592 0 0       0 if($self->hasAttributeNS($ns, $name)) {
593 0         0 my $attribute = delete($self->{'attributes'}->{$ns->ns_prefix}->{$name});
594 0         0 $attribute->delete;
595             }
596             }
597              
598             =head2 $element->getAttributeNS( $namespace, $name )
599              
600             Returns an attributes namespace in this element.
601              
602             =cut
603             sub getAttributeNS
604             {
605 0     0 1 0 my ($self, $ns, $name) = @_;
606 0 0       0 if(not ref($ns)) {
607 0         0 confess "You must give ns methods the name space object, not just the URI or Prefix (skipped)";
608             }
609 0         0 my $prefix = $ns->ns_prefix;
610 0 0       0 $prefix = '' if not $prefix;
611 0 0       0 if($self->{'attributes'}->{$prefix}->{$name}) {
612 0         0 return $self->{'attributes'}->{$prefix}->{$name};
613             }
614             }
615              
616             =head2 $element->setAttributeNS( $namespace, $name, $value )
617              
618             Sets an attributes namespace in this element.
619              
620             =cut
621             sub setAttributeNS
622             {
623 0     0 1 0 my ($self, $ns, $name, $value) = @_;
624 0 0       0 if(not ref($ns)) {
625 0         0 confess "You must give ns methods the name space object, not just the URI or Prefix (skipped)";
626             }
627 0         0 my $prefix = $ns->ns_prefix;
628 0         0 $self->{'attributes'}->{$prefix}->{$name} = $self->_get_attribute_object($name, $value, $ns);
629 0 0       0 if(not $self->{'attributes'}->{$prefix}->{$name}) {
630 0         0 warn "setAttributeNS was unable to set the attribute ";
631             }
632             }
633              
634             =head2 $element->cdata( $text )
635              
636             Rerieve and set this elements cdata (non tag cdata form)
637              
638             =cut
639             sub cdata
640             {
641 19     19 1 31 my ($self, $text) = @_;
642 19 50       51 if($self->hasChildren()) {
643 0         0 $self->error(value => "Unable to get cdata for element with children, xml error!");
644 0         0 return;
645             }
646 19 100       189 if(defined($text)) {
647 12 50       33 if(ref($text) =~ /CDATA/) {
648 0         0 $self->{'cdata'} = $text;
649             } else {
650 12         53 $self->{'cdata'} = XML::DOM2::Element::CDATA->new($text, notag => 1);
651             }
652             }
653 19         67 return $self->{'cdata'};
654             }
655              
656             =head2 $element->hasCDATA()
657              
658             Return true if this element has cdata.
659              
660             =cut
661             sub hasCDATA ($) {
662 6     6 1 7 my $self=shift;
663 6         29 return exists($self->{'cdata'});
664             }
665              
666             =head2 $element->document()
667              
668             Return this elements document, returns undef if no document available.
669              
670             =cut
671             sub document
672             {
673 94     94 1 140 my ($self) = @_;
674 94 50       1481 return $self->{'document'} if ref($self->{'document'});
675 0 0       0 if($self->getParent) {
676 0         0 return $self->getParent->document;
677             } else {
678 0         0 confess "Where you expecting an orphaned element ".$self->localName."\n";
679 0         0 return undef;
680             }
681             }
682              
683             =head2 $element->insertBefore( $node, $childNode )
684              
685             =head2 $element->insertChildBefore( $node, $childNode )
686              
687             =head2 $element->insertNodeBefore( $node, $childNode )
688              
689             =head2 $element->insertElementBefore( $node, $childNode )
690              
691             Inserts a new element just before the referenced child.
692              
693             =cut
694             sub insertBefore
695             {
696 0     0 1 0 my ($self, $newChild, $refChild) = @_;
697 0 0       0 return $self->appendElement($newChild) if not $refChild;
698 0         0 my $index = $self->findChildIndex($refChild);
699 0 0       0 return 0 if $index < 0; # NO_FOUND_ERR
700 0         0 return $self->insertAtIndex($newChild, $index);
701             }
702             *insertChildBefore=\&insertBefore;
703             *insertNodeBefore=\&insertBefore;
704             *insertElementBefore=\&insertBefore;
705              
706             =head2 $element->insertAfter( $node, $childNode )
707              
708             =head2 $element->insertChildAfter( $node, $childNode )
709              
710             =head2 $element->insertElementAfter( $node, $childNode )
711              
712             =head2 $element->insertNodeAfter( $node, $childNode )
713              
714             Inserts a new child element just after the referenced child.
715              
716             =cut
717             sub insertAfter
718             {
719 0     0 1 0 my ($self, $newChild, $refChild) = @_;
720 0 0       0 return $self->appendElement($newChild) if not $refChild;
721 0         0 my $index = $self->findChildIndex($refChild);
722 0 0       0 return 0 if $index < 0; # NO_FOUND_ERR
723 0         0 return $self->insertAtIndex($newChild, $index+1);
724             }
725             *insertChildAfter=\&insertAfter;
726             *insertNodeAfter=\&insertAfter;
727             *insertElementAfter=\&insertAfter;
728              
729             =head2 $element->insertSiblingAfter( $node )
730              
731             Inserts the child just after the current element (effects parent).
732              
733             =cut
734             sub insertSiblingAfter
735             {
736 0     0 1 0 my ($self, $newChild) = @_;
737 0 0       0 return $self->getParent->insertAfter($newChild, $self) if $self->getParent;
738 0         0 return 0;
739             }
740              
741             =head2 $element->insertSiblingBefore( $node )
742              
743             Inserts the child just before the current element (effects parent).
744              
745             =cut
746             sub insertSiblingBefore
747             {
748 0     0 1 0 my ($self, $newChild) = @_;
749 0 0       0 return $self->getParent->insertBefore($newChild, $self) if $self->getParent;
750 0         0 return 0;
751             }
752              
753             =head2 $element->replaceChild( $newChild, $oldChild )
754              
755             Replace an old child with a new element, returns old element.
756              
757             =cut
758             sub replaceChild
759             {
760 0     0 1 0 my ($self, $newChild, $oldChild) = @_;
761             # Replace newChild if it is in this list of children already
762 0 0       0 $self->removeChild($newChild) if $newChild->getParent eq $self;
763             # We need the index of the node to replace
764 0         0 my $index = $self->findChildIndex($oldChild);
765 0 0       0 return 0 if($index < 0); # NOT_FOUND_ERR
766             # Replace and bind new node with it's family
767 0         0 $self->removeChildAtIndex($index);
768 0         0 $self->insertChildAtIndex($index);
769 0         0 return $oldChild;
770             }
771              
772             =head2 $element->replaceElement( $newElement )
773              
774             =head2 $element->replaceNode( $newElement )
775              
776             Replace an old element with a new element in the parents context; element becomes orphaned.
777              
778             =cut
779             sub replaceElement
780             {
781 0     0 1 0 my ($self, $newElement) = @_;
782 0         0 return $self->getParent->replaceChild($newElement, $self);
783             }
784             *replaceNode=\&replaceElement;
785              
786             =head2 $element->removeChild( $child )
787              
788             Remove a child from this element, returns the orphaned element.
789              
790             =cut
791             sub removeChild
792             {
793 0     0 1 0 my ($self, $oldChild) = @_;
794 0         0 my $index = $self->findChildIndex($oldChild);
795 0 0 0     0 return 0 if(not defined $index or $index < 0); # NOT_FOUND_ERR
796 0         0 return $self->removeChildAtIndex($index);
797             }
798              
799             =head2 $element->removeElement()
800              
801             =head2 $element->removeNode()
802              
803             Removes this element from it's parent; element becomes orphaned.
804              
805             =cut
806             sub removeElement
807             {
808 0     0 1 0 my ($self) = @_;
809 0         0 return $self->getParent->removeChild($self);
810             }
811             *removeNode=\&removeElement;
812              
813             =head2 $element->appendChild( $node )
814              
815             =head2 $element->appendElement( $node )
816              
817             =head2 $element->appendNode( $node )
818              
819             Adds the new child to the end of this elements children list.
820              
821             =cut
822             sub appendChild
823             {
824 18     18 1 25 my ($self, $element) = @_;
825 18   100     64 return $self->insertAtIndex( $element, scalar($self->getChildren) || 0 );
826             }
827             *appendElement=\&appendChild;
828             *appendNode=\&appendChild;
829              
830             =head2 $element->cloneNode( $deep )
831              
832             =head2 $element->cloneElement( $deep )
833              
834             Clones the current element, deep allows all child elements to be cloned.
835             The new element is an orphan with all the same id's and atributes as this element.
836              
837             =cut
838             sub cloneNode
839             {
840 0     0 1 0 my ($self, $deep) = @_;
841 0         0 my $clone = XML::DOM2::Element->new($self->localName);
842 0         0 foreach my $key (keys(%{$self})) {
  0         0  
843 0 0 0     0 if($key ne 'children' and $key ne 'parent') {
844 0         0 $clone->{$key} = $self->{$key};
845             }
846             }
847             # We need to clone the children if deep is specified.
848 0 0       0 if($deep) {
849 0         0 foreach my $child ($self->getChilden) {
850 0         0 my $childClone = $child->cloneNode($deep);
851 0         0 $clone->appendChild($childClone);
852             }
853             }
854 0         0 return $clone;
855             }
856             *cloneElement=\&cloneNode;
857              
858             =head2 $element->findChildIndex( $child )
859              
860             Scans through children trying to find this child in the list.
861              
862             =cut
863             sub findChildIndex
864             {
865 0     0 1 0 my ($self, $refChild) = @_;
866 0         0 my $index;
867 0         0 foreach my $child ($self->getChildren) {
868 0 0       0 return $index if $child eq $refChild;
869 0         0 $index++;
870             }
871 0         0 return -1;
872             }
873              
874             =head2 $element->insertAtIndex( $node, $index )
875              
876             Adds the new child at the specified index to this element.
877              
878             =cut
879             sub insertAtIndex
880             {
881 18     18 1 28 my ($self, $newChild, $index) = @_;
882 18 50       43 confess "Unable to insertAtIndex no index defined" if not defined($index);
883 18         52 my $id = $newChild->getElementId();
884 18 50       44 if($self->document) {
885 18 50 33     93 if($id && not $self->document->addId($id, $newChild)) {
886 0         0 $self->error($id => "Id already exists in document");
887 0         0 return undef;
888             }
889 18         69 $self->document->addElement($newChild);
890             } else {
891 0         0 warn("Unable to insert element ".$self->getElementName." not document defined");
892 0         0 return 0;
893             }
894             # Remove the child from other documents and nodes
895 18 50       62 $newChild->getParent->removeChild($newChild) if $newChild->getParent;
896              
897             # This index supports the getChildrenByName function
898 18 100       74 if($self->{'child'}->{$newChild->name}) {
899 4         7 push @{$self->{'child'}->{$newChild->name}}, $newChild;
  4         15  
900             } else {
901 14         49 $self->{'child'}->{$newChild->name} = [ $newChild ];
902             }
903              
904             # Set in new parent
905 18         34 splice @{$self->{'children'}}, $index, 0, $newChild;
  18         51  
906 18         53 $newChild->setParent($self);
907 18         41 return 1;
908             }
909              
910             =head2 $element->removeChildAtIndex( $index )
911              
912             Removed the child at index and returns the now orphaned element.
913              
914             =cut
915             sub removeChildAtIndex
916             {
917 0     0 1 0 my ($self, $index) = @_;
918 0         0 my $oldChild = splice @{$self->{'children'}}, $index, 1;
  0         0  
919 0         0 my $id = $oldChild->getElementId();
920 0 0       0 $self->document->removeId($id) if($id);
921 0         0 $self->document->removeElement($oldChild);
922 0         0 $oldChild->setParent(undef);
923 0 0       0 if(not $self->hasChildren) {
924 0         0 delete $self->{'childen'};
925             }
926 0         0 return $oldChild;
927             }
928              
929             =head2 $element->createChildElement( $name, %options )
930              
931             =head2 $element->createElement( $name, %options )
932              
933             Not DOM2, creates a child element, appending to current element.
934              
935             The advantage to using this method is the elements created
936             with $document->createElement create basic element objects or
937             base objects (those specified in the XML base class or it's kin)
938             Elements created with this could offer more complex objects back.
939              
940             Example: an SVG Gradiant will have stop elements under it, creating
941             stop elements with $document->createElement will return an XML::DOM2::Element
942             create a stop element with $element->createChildElement and it will
943             return an SVG2::Element::Gradiant::Stop object (although both would
944             output the same xml) and it would also prevent you from creating invalid
945             child elements such as a group within a text element.
946              
947             $element->createChildElement($name, %opts);
948              
949             =cut
950              
951             sub createChildElement
952             {
953 18     18 1 58 my ($self, $name, %opts) = @_;
954 18         75 my $element = $self->_element_handle($name, %opts, document => $self->document() );
955 18 50       74 if(ref($element) =~ /CDATA/) {
956 0         0 $self->cdata( $element );
957             } else {
958 18         63 $self->appendChild($element);
959             }
960 18         77 return $element;
961             }
962             *createElement=\&createChildElement;
963              
964             =head1 AUTHOR
965              
966             Martin Owens, doctormo@postmaster.co.uk
967              
968             =head1 SEE ALSO
969              
970             perl(1), L, L
971              
972             L DOM at the W3C
973              
974             =cut
975              
976             return 1;