Discussion:
Clone a DOM subtree to the root of a new DOMDocument efficiently ?
Chris Cheung
2003-11-11 05:54:25 UTC
Permalink
Dear all,

Very often I need to clone a DOM subtree to a new DOMDocument and make
the root of the subtree be the document element of the new DOMDocument.
However, it seems that in Xerces-C++/Perl, the document element is
created when creating the DOMDocument (via
DomImplementation::createDocument) and cannot be replaced afterward.
Hence I cannot use the DOMDocument::importNode to directly deep clone the
root node of the source subtree, but rather I have to copy its
attributes and child nodes one by one (in Perl code):

sub element2Doc
{
my ($element) = @_;

# Create a new DOM Document
my $domImpl =
XML::Xerces::DOMImplementationRegistry::getDOMImplementation('LS')

my $newDoc = $domImpl->createDocument($element->getNamespaceURI,
$element->getTagName, undef);

# Need to copy every attribute and every child node,
# (Since these is no API to set document element of a DOMDocument.)
my $newRoot = $newDoc->getDocumentElement();
my $attrs = $element->getAttributes();

for (my $i = 0; $i < $attrs->getLength; $i++)
{
my $attr = $attrs->item($i);
my $nsURI = $attr->getNamespaceURI;
if ($nsURI)
{
# The attribute is qualified
$newRoot->setAttributeNS($nsURI, $attr->getName,
$attr->getValue);
}
else
{
$newRoot->setAttribute($attr->getName, $attr->getValue);
}
}

my @childNodes = $element->getChildNodes();
foreach (@childNodes)
{
my $copiedChild = $newDoc->importNode($_, 1);
$newRoot->appendChild($copiedChild);
}
return $newDoc;
}


Using the Xerces-Perl wrapper over the efficient Xerces-C++ library,
the code runs slowly since a lot of Perl statements are executed each
calls short C++ methods, especially for broad but not deep source DOM
subtree.

Is there any smarter way to do the same thing?
Thank you in advance for any help.
--
Best Regards,

Chris Cheung
Center for Large-Scale Computation

Have a nice day!
Erik Rydgren
2003-11-11 08:04:56 UTC
Permalink
Well I have no problems replacing a document root with the 2.2.0
codebase. I use the following code. The code is pure DOM so no extra
fancy stuff, don't mind the wrapper classes.

cDocument* poDoc1 = GetDOMImplementation().CreateDocument("", "test",
NULL);
cDocument* poDoc2 = GetDOMImplementation().CreateDocument("", "test2",
NULL);
poDoc2->GetDocumentElement()->AppendChild(poDoc2->CreateElement("elem1")
->cast());
poDoc2->GetDocumentElement()->AppendChild(poDoc2->CreateElement("elem2")
->cast());
poDoc2->GetDocumentElement()->AppendChild(poDoc2->CreateElement("elem3")
->cast());

cNode* poClone =
poDoc1->ImportNode(poDoc2->GetDocumentElement()->cast(), true);
poDoc1->ReplaceChild(poClone, poDoc1->GetDocumentElement()->cast());

// HERE the document root of poDoc1 is test2 with 3 children

Best regards
/ Erik
-----Original Message-----
Sent: den 11 november 2003 06:54
Cc: Anthony Chan
Subject: Clone a DOM subtree to the root of a new DOMDocument
efficiently
?
Dear all,
Very often I need to clone a DOM subtree to a new DOMDocument and make
the root of the subtree be the document element of the new
DOMDocument.
However, it seems that in Xerces-C++/Perl, the document element is
created when creating the DOMDocument (via
DomImplementation::createDocument) and cannot be replaced afterward.
Hence I cannot use the DOMDocument::importNode to directly deep clone the
root node of the source subtree, but rather I have to copy its
sub element2Doc
{
# Create a new DOM Document
my $domImpl =
XML::Xerces::DOMImplementationRegistry::getDOMImplementation('LS')
my $newDoc = $domImpl->createDocument($element->getNamespaceURI,
$element->getTagName, undef);
# Need to copy every attribute and every child node,
# (Since these is no API to set document element of a
DOMDocument.)
my $newRoot = $newDoc->getDocumentElement();
my $attrs = $element->getAttributes();
for (my $i = 0; $i < $attrs->getLength; $i++)
{
my $attr = $attrs->item($i);
my $nsURI = $attr->getNamespaceURI;
if ($nsURI)
{
# The attribute is qualified
$newRoot->setAttributeNS($nsURI, $attr->getName,
$attr->getValue);
}
else
{
$newRoot->setAttribute($attr->getName, $attr->getValue);
}
}
{
my $copiedChild = $newDoc->importNode($_, 1);
$newRoot->appendChild($copiedChild);
}
return $newDoc;
}
Using the Xerces-Perl wrapper over the efficient Xerces-C++ library,
the code runs slowly since a lot of Perl statements are executed each
calls short C++ methods, especially for broad but not deep source DOM
subtree.
Is there any smarter way to do the same thing?
Thank you in advance for any help.
--
Best Regards,
Chris Cheung
Center for Large-Scale Computation
Have a nice day!
---------------------------------------------------------------------
Chris Cheung
2003-11-11 08:31:06 UTC
Permalink
Dear Erik,

That exactly solved my problem. Thank you very much!
Post by Erik Rydgren
Well I have no problems replacing a document root with the 2.2.0
codebase. I use the following code. The code is pure DOM so no extra
fancy stuff, don't mind the wrapper classes.
cDocument* poDoc1 = GetDOMImplementation().CreateDocument("", "test",
NULL);
cDocument* poDoc2 = GetDOMImplementation().CreateDocument("", "test2",
NULL);
poDoc2->GetDocumentElement()->AppendChild(poDoc2->CreateElement("elem1")
->cast());
poDoc2->GetDocumentElement()->AppendChild(poDoc2->CreateElement("elem2")
->cast());
poDoc2->GetDocumentElement()->AppendChild(poDoc2->CreateElement("elem3")
->cast());
cNode* poClone =
poDoc1->ImportNode(poDoc2->GetDocumentElement()->cast(), true);
poDoc1->ReplaceChild(poClone, poDoc1->GetDocumentElement()->cast());
// HERE the document root of poDoc1 is test2 with 3 children
Best regards
/ Erik
-----Original Message-----
Sent: den 11 november 2003 06:54
Cc: Anthony Chan
Subject: Clone a DOM subtree to the root of a new DOMDocument
efficiently
?
Dear all,
Very often I need to clone a DOM subtree to a new DOMDocument and
make
the root of the subtree be the document element of the new
DOMDocument.
However, it seems that in Xerces-C++/Perl, the document element is
created when creating the DOMDocument (via
DomImplementation::createDocument) and cannot be replaced afterward.
Hence I cannot use the DOMDocument::importNode to directly deep clone
the
root node of the source subtree, but rather I have to copy its
--
Best Regards,

Chris Cheung
Center for Large-Scale Computation

Have a nice day!
Loading...