| XML-DOM2 documentation | Contained in the XML-DOM2 distribution. |
XML::DOM2::DOM::Element - A library of DOM (Document Object Model) methods for XML Elements.
Provides all the DOM method for XML Elements
Returns the elements first child in it's children list
Returns the elements last child in it's children list
Return the array index of this element in the parent or the passed list (if there is one).
Return the element at the specified index (the index can be negative).
Return the next element to this element in the parents child list.
Return the previous element to this element in the parents child list.
Returns all the elements children.
Returns all the elements children with that tag name (including namespace prefix).
Returns 1 if this element has children.
Returns the object of the parent element.
$element->setParent($parent);
Sets the parent node, used internaly.
Return a list of the parents of the current element, starting from the immediate parent. The last member of the list should be the document element.
Returns true if the current element is an ancestor of the descendant element.
Return true if the crrent element is the descendant of the ancestor element.
Returns a list of sibling elements.
Returns true if the elements has sibling elements.
Return a string containing the name (i.e. the type, not the Id) of an element.
Return a string containing the elements Id (unique identifier string).
Returns the specified attribute in the element, will return a serialised string instead of posible attribute object if serialise set.
Returns a list of attributes in various forms.
Returns a list of attribute names, used internaly.
Returns a list of attribute names, used internaly.
Returns a list of attribute names, used internaly.
Returns true if this element as this attribute.
Returns true if this attribute in this namespace is in this element.
Return true is element has any attributes
Set an attribute on this element, it will accept serialised strings or objects.
Remove a single attribute from this element.
Remove a single attribute from this element.
Returns an attributes namespace in this element.
Sets an attributes namespace in this element.
Rerieve and set this elements cdata (non tag cdata form)
Return true if this element has cdata.
Return this elements document, returns undef if no document available.
Inserts a new element just before the referenced child.
Inserts a new child element just after the referenced child.
Inserts the child just after the current element (effects parent).
Inserts the child just before the current element (effects parent).
Replace an old child with a new element, returns old element.
Replace an old element with a new element in the parents context; element becomes orphaned.
Remove a child from this element, returns the orphaned element.
Removes this element from it's parent; element becomes orphaned.
Adds the new child to the end of this elements children list.
Clones the current element, deep allows all child elements to be cloned. The new element is an orphan with all the same id's and atributes as this element.
Scans through children trying to find this child in the list.
Adds the new child at the specified index to this element.
Removed the child at index and returns the now orphaned element.
Not DOM2, creates a child element, appending to current element.
The advantage to using this method is the elements created with $document->createElement create basic element objects or base objects (those specified in the XML base class or it's kin) Elements created with this could offer more complex objects back.
Example: an SVG Gradiant will have stop elements under it, creating stop elements with $document->createElement will return an XML::DOM2::Element create a stop element with $element->createChildElement and it will return an SVG2::Element::Gradiant::Stop object (although both would output the same xml) and it would also prevent you from creating invalid child elements such as a group within a text element.
$element->createChildElement($name, %opts);
Martin Owens, doctormo@postmaster.co.uk
perl(1), XML::DOM2, XML::DOM2::Element
http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/level-one-core.html DOM at the W3C
| XML-DOM2 documentation | Contained in the XML-DOM2 distribution. |
package XML::DOM2::DOM::Element;
use base "XML::DOM2::DOM::NameSpace"; use strict; use Carp;
sub getFirstChild ($) { my $self=shift; if (my @children=$self->getChildren) { return $children[0]; } return undef; } *firstChild=\&getFirstChild;
sub getLastChild ($) { my $self=shift; if (my @children=$self->getChildren) { return $children[-1]; } return undef; } *lastChild=\&getLastChild;
sub getChildIndex ($;@) { my ($self,@children)=@_; unless (@children) { my $parent=$self->getParent(); @children=$parent->getChildren(); return undef unless @children; } for my $index (0..$#children) { return $index if $children[$index] == $self; } return undef; }
sub getChildAtIndex ($$;@) { my ($self,$index,@children)=@_; unless (@children) { my $parent=$self->getParent(); @children=$parent->getChildren(); return undef unless @children; } return $children[$index]; }
sub getNextSibling ($) { my $self=shift; if (my $parent=$self->getParent) { my @children=$parent->getChildren(); my $index=$self->getChildIndex(@children); if (defined $index and scalar(@children)>$index) { return $children[$index+1]; } } return undef; } *nextSibling=\&getNextSibling;
sub getPreviousSibling ($) { my $self=shift; if (my $parent=$self->getParent) { my @children=$parent->getChildren(); my $index=$self->getChildIndex(@children); if ($index) { return $children[$index-1]; } } return undef; } *previousSibling=\&getPreviousSibling;
sub getChildren ($) { my $self=shift; if ($self->{'children'}) { return @{$self->{'children'}}; } return (); } *getChildElements=\&getChildren; *getChildNodes=\&getChildren;
sub getChildrenByName { my ($self, $name) = @_; if(defined($self->{'child'}->{$name})) { if(wantarray) { return @{$self->{'child'}->{$name}}; } else { return $self->{'child'}->{$name}->[0]; } } }
sub hasChildren ($) { my $self=shift; if (exists $self->{'children'}) { if (scalar @{$self->{'children'}}) { return 1; } } return 0; } *hasChildElements=\&hasChildren; *hasChildNodes=\&hasChildren;
sub getParent ($) { my $self=shift; if ($self->{'parent'}) { return $self->{'parent'}; } return undef; } *getParentElement=\&getParent; *getParentNode=\&getParent;
sub setParent ($$) { my ($self,$parent) = @_; if(ref($parent) or not defined($parent)) { $self->{'parent'} = $parent; return 1; } return undef; } *setParentElement=\&setParent;
sub getParents { my $self=shift; my $parent = $self->getParent; return undef unless $parent; my @parents; while ($parent) { push @parents,$parent; $parent=$parent->getParent; } return @parents; } *getParentElements=\&getParents; *getParentNodes=\&getParents; *getAncestors=\&getParents;
sub isAncestor ($$) { my ($self,$descendant)=@_; my @parents=$descendant->getParents(); foreach my $parent (@parents) { return 1 if $parent==$self; } return 0; }
sub isDescendant ($$) { my ($self,$ancestor)=@_; my @parents=$self->getParents(); foreach my $parent (@parents) { return 1 if $parent==$ancestor; } return 0; }
sub getSiblings ($) { my $self=shift; if (my $parent=$self->getParent) { return $parent->getChildren(); } return wantarray?():undef; }
sub hasSiblings ($) { my $self=shift; if (my $parent=$self->getParent) { my $siblings=scalar($parent->getChildren); return 1 if $siblings>=2; } return undef; }
sub getElementName ($) { my $self=shift; return $self->name; } *getType=\&getElementName; *getElementType=\&getElementName; *getTagName=\&getElementName; *getTagType=\&getElementName; *getNodeName=\&getElementName; *getNodeType=\&getElementName;
sub getElementId ($) { my $self=shift; if (exists $self->{id}) { return $self->{id}; } return undef; }
sub getAttribute { my ($self, $name) = @_; my $attribute = $self->{'attributes'}->{''}->{$name}; return $attribute; }
sub getAttributes { my ($self, $serialise, $ns) = @_; my @names = $self->getAttributeNamesNS($ns); my %attributes; my @attributes; foreach my $nsr (@names) { my ($sns, $name) = @{$nsr}; my $attribute; if($sns) { $attribute = $self->getAttributeNS($sns, $name, $serialise); } else { $attribute = $self->getAttribute($name, $serialise); } if(not defined($attribute)) { die "Something is very wrong with the attributes"; } if(not ref($attribute)) { die "An attribute should always be an object: ($name:$attribute) ".$self->name."\n"; } if($serialise <= 1) { $attributes{$attribute->name} = $attribute; } else { push @attributes, $attribute->serialise_full; } } if($serialise <= 1) { return wantarray ? %attributes : \%attributes; } elsif($serialise == 2) { return wantarray ? @attributes : \@attributes; } else { return join(' ', @attributes); } }
sub getAttributeNames { my ($self, $ns) = @_; my $prefix = $ns ? $ns->ns_prefix : ''; warn "The prefix is undefined!" if not defined($prefix); my @names; foreach my $name (keys(%{$self->{'attributes'}->{$prefix}})) { push @names, $name; } return wantarray ? @names : \@names; }
sub getAttributeNamesNS { my ($self, $ns) = @_; # Default Namespace my @names; # Get all other name spaces my @ns = $ns ? ($ns) : $self->getAttributeNamespaces; foreach my $sns (@ns) { if(defined($sns)) { foreach my $name ($self->getAttributeNames($sns)) { push @names, [ $sns, $name ]; } } else { warn "One of the name spaces is not defined\n"; } } return @names; }
sub getAttributeNamespaces { my ($self) = @_; return map { $_ ne '' ? $self->document->getNamespace($_) : '' } keys(%{$self->{'attributes'}}); }
sub hasAttribute { my ($self, $name) = @_; return 1 if exists( $self->{'attributes'}->{''}->{$name} ); }
sub hasAttributeNS { my ($self, $ns, $name) = @_; my $prefix = $ns->ns_prefix; return 1 if exists( $self->{'attributes'}->{$prefix}->{$name} ); }
sub hasAttributes { my ($self) = @_; return 1 if $self->{'attributes'} and keys(%{ $self->{'attributes'} }) }
sub setAttribute { my ($self, $name, $value) = @_; confess "Name is not defined" if not $name; my $existing = $self->getAttribute($name); # This ensures that ids are updated in a sane way. if ($name eq "id" and $self->document and defined($value)) { # Set the new id if($self->document->addId($value, $self)) { if($existing) { # Remove the old id my $oldvalue = $existing->serialise; $self->document->removeId($oldvalue); } } else { $self->error('setAttribute', "Id '$value' already exists in document, unable to modify attribute"); return undef; } } # Some elements can't contain attributes $self->{'attributes'}->{''}->{$name} = $self->_get_attribute_object( $name, $value, undef, $existing ); return 1; } sub _get_attribute_object { my ($self, $name, $value, $ns, $existing) = @_; if(not $self->_can_contain_attributes) { $self->error('setAttribute', "This Element can not contain attributes. (".$self->getElementName.")"); return undef; } # undef means delete attribute return $self->removeAttribute($name) if not defined($value); my $result; # This is to handle attributes handled by objects if($self->_has_attribute($name)) { $result = $existing; if(not $result) { # Create a new attribute $result = $self->_attribute_handle( $name, name => $name, namespace => $ns, owner => $self ); } croak "Unable to setAttribute, _attribute_handle does not exist (".ref($self).":$name)" if not ref($result); $result->deserialise($value); } return $result; }
sub removeAttribute { my ($self, $name) = @_; if($self->hasAttribute($name)) { my $attribute = delete($self->{'attributes'}->{''}->{$name}); $attribute->delete; } }
sub removeAttributeNS { my ($self, $ns, $name) = @_; if($self->hasAttributeNS($ns, $name)) { my $attribute = delete($self->{'attributes'}->{$ns->ns_prefix}->{$name}); $attribute->delete; } }
sub getAttributeNS { my ($self, $ns, $name) = @_; if(not ref($ns)) { confess "You must give ns methods the name space object, not just the URI or Prefix (skipped)"; } my $prefix = $ns->ns_prefix; $prefix = '' if not $prefix; if($self->{'attributes'}->{$prefix}->{$name}) { return $self->{'attributes'}->{$prefix}->{$name}; } }
sub setAttributeNS { my ($self, $ns, $name, $value) = @_; if(not ref($ns)) { confess "You must give ns methods the name space object, not just the URI or Prefix (skipped)"; } my $prefix = $ns->ns_prefix; $self->{'attributes'}->{$prefix}->{$name} = $self->_get_attribute_object($name, $value, $ns); if(not $self->{'attributes'}->{$prefix}->{$name}) { warn "setAttributeNS was unable to set the attribute "; } }
sub cdata { my ($self, $text) = @_; if($self->hasChildren()) { $self->error(value => "Unable to get cdata for element with children, xml error!"); return; } if(defined($text)) { if(ref($text) =~ /CDATA/) { $self->{'cdata'} = $text; } else { $self->{'cdata'} = XML::DOM2::Element::CDATA->new($text, notag => 1); } } return $self->{'cdata'}; }
sub hasCDATA ($) { my $self=shift; return exists($self->{'cdata'}); }
sub document { my ($self) = @_; return $self->{'document'} if ref($self->{'document'}); if($self->getParent) { return $self->getParent->document; } else { confess "Where you expecting an orphaned element ".$self->localName."\n"; return undef; } }
sub insertBefore { my ($self, $newChild, $refChild) = @_; return $self->appendElement($newChild) if not $refChild; my $index = $self->findChildIndex($refChild); return 0 if $index < 0; # NO_FOUND_ERR return $self->insertAtIndex($newChild, $index); } *insertChildBefore=\&insertBefore; *insertNodeBefore=\&insertBefore; *insertElementBefore=\&insertBefore;
sub insertAfter { my ($self, $newChild, $refChild) = @_; return $self->appendElement($newChild) if not $refChild; my $index = $self->findChildIndex($refChild); return 0 if $index < 0; # NO_FOUND_ERR return $self->insertAtIndex($newChild, $index+1); } *insertChildAfter=\&insertAfter; *insertNodeAfter=\&insertAfter; *insertElementAfter=\&insertAfter;
sub insertSiblingAfter { my ($self, $newChild) = @_; return $self->getParent->insertAfter($newChild, $self) if $self->getParent; return 0; }
sub insertSiblingBefore { my ($self, $newChild) = @_; return $self->getParent->insertBefore($newChild, $self) if $self->getParent; return 0; }
sub replaceChild { my ($self, $newChild, $oldChild) = @_; # Replace newChild if it is in this list of children already $self->removeChild($newChild) if $newChild->getParent eq $self; # We need the index of the node to replace my $index = $self->findChildIndex($oldChild); return 0 if($index < 0); # NOT_FOUND_ERR # Replace and bind new node with it's family $self->removeChildAtIndex($index); $self->insertChildAtIndex($index); return $oldChild; }
sub replaceElement { my ($self, $newElement) = @_; return $self->getParent->replaceChild($newElement, $self); } *replaceNode=\&replaceElement;
sub removeChild { my ($self, $oldChild) = @_; my $index = $self->findChildIndex($oldChild); return 0 if(not defined $index or $index < 0); # NOT_FOUND_ERR return $self->removeChildAtIndex($index); }
sub removeElement { my ($self) = @_; return $self->getParent->removeChild($self); } *removeNode=\&removeElement;
sub appendChild { my ($self, $element) = @_; return $self->insertAtIndex( $element, scalar($self->getChildren) || 0 ); } *appendElement=\&appendChild; *appendNode=\&appendChild;
sub cloneNode { my ($self, $deep) = @_; my $clone = XML::DOM2::Element->new($self->localName); foreach my $key (keys(%{$self})) { if($key ne 'children' and $key ne 'parent') { $clone->{$key} = $self->{$key}; } } # We need to clone the children if deep is specified. if($deep) { foreach my $child ($self->getChilden) { my $childClone = $child->cloneNode($deep); $clone->appendChild($childClone); } } return $clone; } *cloneElement=\&cloneNode;
sub findChildIndex { my ($self, $refChild) = @_; my $index; foreach my $child ($self->getChildren) { return $index if $child eq $refChild; $index++; } return -1; }
sub insertAtIndex { my ($self, $newChild, $index) = @_; confess "Unable to insertAtIndex no index defined" if not defined($index); my $id = $newChild->getElementId(); if($self->document) { if($id && not $self->document->addId($id, $newChild)) { $self->error($id => "Id already exists in document"); return undef; } $self->document->addElement($newChild); } else { warn("Unable to insert element ".$self->getElementName." not document defined"); return 0; } # Remove the child from other documents and nodes $newChild->getParent->removeChild($newChild) if $newChild->getParent; # This index supports the getChildrenByName function if($self->{'child'}->{$newChild->name}) { push @{$self->{'child'}->{$newChild->name}}, $newChild; } else { $self->{'child'}->{$newChild->name} = [ $newChild ]; } # Set in new parent splice @{$self->{'children'}}, $index, 0, $newChild; $newChild->setParent($self); return 1; }
sub removeChildAtIndex { my ($self, $index) = @_; my $oldChild = splice @{$self->{'children'}}, $index, 1; my $id = $oldChild->getElementId(); $self->document->removeId($id) if($id); $self->document->removeElement($oldChild); $oldChild->setParent(undef); if(not $self->hasChildren) { delete $self->{'childen'}; } return $oldChild; }
sub createChildElement { my ($self, $name, %opts) = @_; my $element = $self->_element_handle($name, %opts, document => $self->document() ); if(ref($element) =~ /CDATA/) { $self->cdata( $element ); } else { $self->appendChild($element); } return $element; } *createElement=\&createChildElement;
return 1;