Subject: | SVG::DOM insertAtIndex() does not update -docref, -elist, -idlist properly if newChild has children |
Date: | Mon, 28 Nov 2011 14:49:16 -0600 |
To: | bug-SVG [...] rt.cpan.org |
From: | Ryan Christensen <rgc255 [...] gmail.com> |
I found that if I use SVG::Parser to parse an existing SVG file and then I
extract an element/node from the SVG object returned
by SVG::Parser::parsefile via getElementByID, I get a lot of error messages
when I try to append the node from the parsed SVG object
insertAtIndex() in SVG::DOM only updates the -elist and -idlist hashes of
arrays properly if the child being added ($newChild) has no children. If
$newChild has children (which may in turn have children of their own, etc),
then the -docref value is not set to the correct value ($self->{-docref}),
and the $self->{-docref}->{-elist} and $self->{-docref}->{-idlist} data
structures are not updated properly.
I ran into this problem when trying to append nodes with multiple children
taken from an SVG object returned by a call to parsefile() in SVG::Parser
to a new SVG object that I had created:
my $newSVG = SVG->new();
$parser = new SVG::Parser();
$svg_in = $parser->parsefile($svgFilePath);
$logoObj = $svg_in->getElementByID('logo')->cloneNode(1);
$newSVG->appendChild($logoObj);
# the xmlify() sub routine call resulted in error messages every
time the -docref value was accessed for one of the children of the main
parent node in the $logoObj.
print $newSVG->xmlify();
I fixed this problem by modifying some sub routines in the SVG::DOM package
and appending them to my own script:
....
my_appendChild($newSVG, $logoObj);
print $newSVG->xmlify();
# based on appendChild from SVG::DOM
sub my_appendChild
{
my ($self, $element) = @_;
my $index = (defined $self->{-childs} && scalar @{$self->{-childs}}) ||
0;
my_insertAtIndex($self, $element, $index);
return 1;
}
# based on appendChild from SVG::DOM
sub my_insertAtIndex
{
my ($self, $newChild, $index) = @_;
# add child
splice @{$self->{-childs}}, $index, 0, $newChild;
update_docref_idlist_elist($self, $newChild);
return 1;
}
sub update_docref_idlist_elist
{
my ($self, $newChild) = @_;
# update parent and document reference
$newChild->{-docref} = $self->{-docref};
weaken( $newChild->{-docref} );
$newChild->{-parent} = $self;
weaken( $newChild->{-parent} );
# update ID and element list
if ( defined($newChild->{id}) )
{
$self->{-docref}->{-idlist}->{ $newChild->{id} } = $newChild;
}
# create -elist if it doesn't exist yet
if ( !defined $self->{-docref}->{-elist} )
{
$self->{-docref}->{-elist} = {}
}
# if no entree in -elist exists yet for $newChild->{-name} tag, create
an empty array for this tag
if ( !defined $self->{-docref}->{-elist}->{ $newChild->{-name} } )
{
$self->{-docref}->{-elist}->{ $newChild->{-name} } = []
}
# add the $newChild to the 'front' of the -elist array
unshift @{ $self->{-docref}->{-elist}->{ $newChild->{-name} } },
$newChild;
# check to see if $newChild has children.
my @children = $newChild->getChildren();
foreach my $child(@children)
{
# if $newChild has children, recursively update each child's -docref
value. Also update -elist and -idlist
update_docref_idlist_elist($self, $child)
}
return 1;
}