* reversedIdentifiers is null, the parameter is not applied.
*/
private Node importNode(Node source, boolean deep, boolean cloningDoc,
HashMap reversedIdentifiers)
throws DOMException {
Node newnode=null;
Hashtable userData = null;
// Sigh. This doesn't work; too many nodes have private data that
// would have to be manually tweaked. May be able to add local
// shortcuts to each nodetype. Consider ?????
// if(source instanceof NodeImpl &&
// !(source instanceof DocumentImpl))
// {
// // Can't clone DocumentImpl since it invokes us...
// newnode=(NodeImpl)source.cloneNode(false);
// newnode.ownerDocument=this;
// }
// else
if(source instanceof NodeImpl)
userData = ((NodeImpl)source).getUserDataRecord();
int type = source.getNodeType();
switch (type) {
case ELEMENT_NODE: {
Element newElement;
boolean domLevel20 = source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0");
// Create element according to namespace support/qualification.
if(domLevel20 == false || source.getLocalName() == null)
newElement = createElement(source.getNodeName());
else
newElement = createElementNS(source.getNamespaceURI(),
source.getNodeName());
// Copy element's attributes, if any.
NamedNodeMap sourceAttrs = source.getAttributes();
if (sourceAttrs != null) {
int length = sourceAttrs.getLength();
for (int index = 0; index < length; index++) {
Attr attr = (Attr)sourceAttrs.item(index);
// NOTE: this methods is used for both importingNode
// and cloning the document node. In case of the
// clonning default attributes should be copied.
// But for importNode defaults should be ignored.
if (attr.getSpecified() || cloningDoc) {
Attr newAttr = (Attr)importNode(attr, true, cloningDoc,
reversedIdentifiers);
// Attach attribute according to namespace
// support/qualification.
if (domLevel20 == false ||
attr.getLocalName() == null)
newElement.setAttributeNode(newAttr);
else
newElement.setAttributeNodeNS(newAttr);
}
}
}
// Register element identifier.
if (reversedIdentifiers != null) {
// Does element have an associated identifier?
Object elementId = reversedIdentifiers.get(source);
if (elementId != null) {
if (identifiers == null)
identifiers = new Hashtable();
identifiers.put(elementId, newElement);
}
}
newnode = newElement;
break;
}
case ATTRIBUTE_NODE: {
if( source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0") ){
if (source.getLocalName() == null) {
newnode = createAttribute(source.getNodeName());
} else {
newnode = createAttributeNS(source.getNamespaceURI(),
source.getNodeName());
}
}
else {
newnode = createAttribute(source.getNodeName());
}
// if source is an AttrImpl from this very same implementation
// avoid creating the child nodes if possible
if (source instanceof AttrImpl) {
AttrImpl attr = (AttrImpl) source;
if (attr.hasStringValue()) {
AttrImpl newattr = (AttrImpl) newnode;
newattr.setValue(attr.getValue());
deep = false;
}
else {
deep = true;
}
}
else {
// According to the DOM spec the kids carry the value.
// However, there are non compliant implementations out
// there that fail to do so. To avoid ending up with no
// value at all, in this case we simply copy the text value
// directly.
if (source.getFirstChild() == null) {
newnode.setNodeValue(source.getNodeValue());
deep = false;
} else {
deep = true;
}
}
break;
}
case TEXT_NODE: {
newnode = createTextNode(source.getNodeValue());
break;
}
case CDATA_SECTION_NODE: {
newnode = createCDATASection(source.getNodeValue());
break;
}
case ENTITY_REFERENCE_NODE: {
newnode = createEntityReference(source.getNodeName());
// the subtree is created according to this doc by the method
// above, so avoid carrying over original subtree
deep = false;
break;
}
case ENTITY_NODE: {
Entity srcentity = (Entity)source;
EntityImpl newentity =
(EntityImpl)createEntity(source.getNodeName());
newentity.setPublicId(srcentity.getPublicId());
newentity.setSystemId(srcentity.getSystemId());
newentity.setNotationName(srcentity.getNotationName());
// Kids carry additional value,
// allow deep import temporarily
newentity.isReadOnly(false);
newnode = newentity;
break;
}
case PROCESSING_INSTRUCTION_NODE: {
newnode = createProcessingInstruction(source.getNodeName(),
source.getNodeValue());
break;
}
case COMMENT_NODE: {
newnode = createComment(source.getNodeValue());
break;
}
case DOCUMENT_TYPE_NODE: {
// unless this is used as part of cloning a Document
// forbid it for the sake of being compliant to the DOM spec
if (!cloningDoc) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
}
DocumentType srcdoctype = (DocumentType)source;
DocumentTypeImpl newdoctype = (DocumentTypeImpl)
createDocumentType(srcdoctype.getNodeName(),
srcdoctype.getPublicId(),
srcdoctype.getSystemId());
newdoctype.setInternalSubset(srcdoctype.getInternalSubset());
// Values are on NamedNodeMaps
NamedNodeMap smap = srcdoctype.getEntities();
NamedNodeMap tmap = newdoctype.getEntities();
if(smap != null) {
for(int i = 0; i < smap.getLength(); i++) {
tmap.setNamedItem(importNode(smap.item(i), true, true,
reversedIdentifiers));
}
}
smap = srcdoctype.getNotations();
tmap = newdoctype.getNotations();
if (smap != null) {
for(int i = 0; i < smap.getLength(); i++) {
tmap.setNamedItem(importNode(smap.item(i), true, true,
reversedIdentifiers));
}
}
// NOTE: At this time, the DOM definition of DocumentType
// doesn't cover Elements and their Attributes. domimpl's
// extentions in that area will not be preserved, even if
// copying from domimpl to domimpl. We could special-case
// that here. Arguably we should. Consider. ?????
newnode = newdoctype;
break;
}
case DOCUMENT_FRAGMENT_NODE: {
newnode = createDocumentFragment();
// No name, kids carry value
break;
}
case NOTATION_NODE: {
Notation srcnotation = (Notation)source;
NotationImpl newnotation =
(NotationImpl)createNotation(source.getNodeName());
newnotation.setPublicId(srcnotation.getPublicId());
newnotation.setSystemId(srcnotation.getSystemId());
// Kids carry additional value
newnode = newnotation;
// No name, no value
break;
}
case DOCUMENT_NODE : // Can't import document nodes
default: { // Unknown node type
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
}
}
if(userData != null)
callUserDataHandlers(source, newnode, UserDataHandler.NODE_IMPORTED,userData);
// If deep, replicate and attach the kids.
if (deep) {
for (Node srckid = source.getFirstChild();
srckid != null;
srckid = srckid.getNextSibling()) {
newnode.appendChild(importNode(srckid, true, cloningDoc,
reversedIdentifiers));
}
}
if (newnode.getNodeType() == Node.ENTITY_NODE) {
((NodeImpl)newnode).setReadOnly(true, true);
}
return newnode;
} // importNode(Node,boolean,boolean,Hashtable):Node