/usr/local/CPAN/XML-DOM-Lite/XML/DOM/Lite/Node.pm
package XML::DOM::Lite::Node;
use Scalar::Util qw(weaken);
use XML::DOM::Lite::NodeList;
use XML::DOM::Lite::Constants qw(:all);
sub new {
my ($class, $proto) = @_;
unless (UNIVERSAL::isa($proto->{childNodes}, 'XML::DOM::Lite::NodeList')) {
$proto->{childNodes} = XML::DOM::Lite::NodeList->new(
$proto->{childNodes} || [ ]
);
}
$proto->{attributes} = XML::DOM::Lite::NodeList->new([ ])
unless defined $proto->{attributes};
my $self = bless $proto, $class;
return $self;
}
sub childNodes {
my $self = shift; $self->{childNodes} = shift if @_;
return $self->{childNodes};
}
sub parentNode {
my $self = shift;
if (@_) {
weaken($self->{parentNode} = shift());
} else {
return $self->{parentNode};
}
}
sub documentElement {
weaken($_[0]->{documentElement} = $_[1]) if $_[1]; $_[0]->{documentElement};
}
sub nodeType {
my $self = shift; $self->{nodeType} = shift if @_;
$self->{nodeType};
}
sub nodeName {
my $self = shift; $self->{nodeName} = shift if @_;
$self->{nodeName};
}
sub tagName {
my $self = shift; $self->{tagName} = shift if @_;
$self->{tagName};
}
sub appendChild {
my ($self, $node) = @_;
if ($node->{parentNode}) {
$node->{parentNode}->removeChild($node);
}
unless ($node->nodeType == DOCUMENT_FRAGMENT_NODE) {
$node->{parentNode} = $self;
$self->{childNodes}->insertNode($node);
} else {
while ($node->childNodes->length) {
$self->appendChild($node->firstChild);
}
}
return $node;
}
sub previousSibling {
my $self = shift;
if ($self->parentNode) {
my $index = $self->parentNode->childNodes->nodeIndex($self);
return undef if $index == 0;
return $self->parentNode->childNodes->[$index - 1];
}
}
sub nextSibling {
my $self = shift;
if ($self->parentNode) {
my $index = $self->parentNode->childNodes->nodeIndex($self);
return undef if $index == @{$self->childNodes->length} - 1;
return $self->parentNode->childNodes->[$index + 1];
}
}
sub removeChild {
my ($self, $node) = @_;
if ($node->parentNode == $self) {
undef($node->{parentNode});
return $self->childNodes->removeNode($node);
} else {
die "$node is not a child of $self";
}
}
sub insertBefore {
my ($self, $node, $refNode) = @_;
die "usage error" unless (scalar(@_) == 3);
if ($node->parentNode) {
$node->parentNode->removeChild($node);
}
if ($node->nodeType == DOCUMENT_FRAGMENT_NODE) {
foreach my $c (@{$node->childNodes}) {
$self->insertBefore($c, $refNode);
}
return;
}
$node->parentNode($self);
my $index = $self->childNodes->nodeIndex($refNode);
if (defined $index) {
if ($index <= 0) {
$self->childNodes->insertNode($node, 0);
} else {
$self->childNodes->insertNode($node, $index);
}
} else {
die "$refNode is not a child of $self";
}
}
sub replaceChild {
my ($self, $node, $refNode) = @_;
die "usage error" unless (scalar(@_) == 3);
$self->insertBefore($refNode, $node);
$self->removeChild($refNode);
}
sub nodeValue {
my $self = shift; $self->{nodeValue} = shift if @_;
$self->{nodeValue};
}
sub attributes {
my $self = shift; $self->{attributes} = shift if @_;
return $self->{attributes};
}
sub getAttribute {
my ($self, $attname) = @_;
for (my $x = 0; $x < $self->{attributes}->length; $x++) {
return $self->{attributes}->[$x]->{nodeValue}
if ($self->{attributes}->[$x]->{nodeName} eq $attname);
}
return undef;
}
sub setAttribute {
my ($self, $attname, $value) = @_;
for (my $x = 0; $x < $self->{attributes}->length; $x++) {
if ($self->{attributes}->[$x]->{nodeName} eq $attname) {
$self->{attributes}->[$x]->{nodeValue} = $value;
return $value;
}
}
push @{$self->{attributes}}, XML::DOM::Lite::Node->new({
nodeType => ATTRIBUTE_NODE,
nodeName => $attname,
nodeValue => $value
});
return $value;
}
sub firstChild {
my ($self) = @_;
return $self->childNodes->item(0);
}
sub lastChild {
my ($self) = @_;
return $self->childNodes->[$#{$self->childNodes}];
}
sub ownerDocument {
my $self = shift; weaken($self->{ownerDocument} = shift) if @_;
$self->{ownerDocument};
}
sub getElementsByTagName {
my ($self, $tag_name) = @_;
my $nlist = XML::DOM::Lite::NodeList->new([ ]);
my @stack = @{ $self->childNodes };
while (my $n = shift(@stack)) {
if ($n->nodeType == ELEMENT_NODE) {
if ($n->tagName eq $tag_name) {
$nlist->insertNode($n);
}
push @stack, @{ $n->childNodes };
}
}
return $nlist;
}
sub cloneNode {
my ($self, $deep) = @_;
my $copy = { };
@copy{keys %$self} = values %$self;
$copy->{childNodes} = XML::DOM::Lite::NodeList->new([ ]);
$copy->{attributes} = XML::DOM::Lite::NodeList->new([@{$self->attributes}]);
$copy->{tagName} = $self->tagName;
$copy->{nodeName} = $self->nodeName;
$copy->{nodeType} = $self->nodeType;
$copy->{ownerDocument} = $self->ownerDocument;
bless $copy, ref($self);
if ($deep) {
foreach (@{$self->childNodes}) {
$copy->childNodes->insertNode($_->cloneNode($deep));
}
}
return $copy;
}
sub xml {
my $self = shift;
require XML::DOM::Lite::Serializer;
my $serializer = XML::DOM::Lite::Serializer->new();
return $serializer->serializeToString( $self );
}
1;