5

I've been looking arround the web, and I'm fairly sure I already know the answer ("no"), but I'd like to check:

Does IE support importNode() yet? Is there a better alternative than walking the DOM and creating nodes? (I've seen the clasic article by Anthony Holdener but its more than a year old now, and I'm hoping that either IE has evolved, or someone has another workarround)

Thanks.

Moose Morals
  • 1,628
  • 25
  • 32
  • Here's a [related question with an implementation](http://stackoverflow.com/a/6075604/405017). – Phrogz Mar 26 '12 at 11:38

3 Answers3

5

There is a function document.importNode() in Internet Explorer 9 DOM API. However, IE9 throws a script error when it's called

SCRIPT16386: No such interface supported

Also there is need to define namespace of source node (e.g., when we want to import SVG - In IE9, Imported nodes do not seem to be recognized as SVG Elements)

Phrogz suggested this useful workaround. However, when we import element which has special namespace (declared in xmlns attribute, e.g. <svg xmlns="http://www.w3.org/2000/svg" …>…</svg>) there will be error in clone.setAttributeNS(a.namespaceURI,a.nodeName,a.nodeValue) because namespaceURI for attribute xmlns is null.

There is workaround which work for me:

var newNode;
try {
  newNode = document.importNode(sourceDocumentElement, true);
}
catch(e) {
  newNode = importNode(sourceDocumentElement, true);
}

function importNode(node, allChildren) {
  switch (node.nodeType) {
    case document.ELEMENT_NODE:
      var newNode = document.createElementNS(node.namespaceURI, node.nodeName);
      if(node.attributes && node.attributes.length > 0)
        for(var i = 0, il = node.attributes.length; i < il; i++)
          newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i].nodeName));
      if(allChildren && node.childNodes && node.childNodes.length > 0)
        for(var i = 0, il = node.childNodes.length; i < il; i++)
          newNode.appendChild(importNode(node.childNodes[i], allChildren));
      return newNode;
      break;
    case document.TEXT_NODE:
    case document.CDATA_SECTION_NODE:
    case document.COMMENT_NODE:
      return document.createTextNode(node.nodeValue);
      break;
  }
}
Community
  • 1
  • 1
resnyanskiy
  • 1,607
  • 1
  • 24
  • 24
  • This works great for me, but I'm having a problem where elements are showing up as broken images (in IE9). Any idea why this would happen? I have verified that the image URLs are valid, so that is definitely not the problem. Thanks! – lakenen Jan 29 '13 at 21:21
  • In case anyone is interested, I [solved the problem](http://stackoverflow.com/questions/14593520/ie9-importing-inline-svg-image-elements-broken). – lakenen Jan 29 '13 at 23:07
4

I haven't heard this has changed yet, and in a recent post by John Resig, he states:

Internet Explorer doesn't support importNode or adoptNode

Also see this A List Apart article on cross-browser importnode() as it includes a specific work-around for Internet Explorer.

To quote for posterity,

The solution to all of my problems was to not use a DOM method after all, and instead use my own implementation. Here, in all of its glory, is my final solution to the importNode() problem coded in a cross-browser compliant way: (Line wraps marked » —Ed.)

if (!document.ELEMENT_NODE) {
  document.ELEMENT_NODE = 1;
  document.ATTRIBUTE_NODE = 2;
  document.TEXT_NODE = 3;
  document.CDATA_SECTION_NODE = 4;
  document.ENTITY_REFERENCE_NODE = 5;
  document.ENTITY_NODE = 6;
  document.PROCESSING_INSTRUCTION_NODE = 7;
  document.COMMENT_NODE = 8;
  document.DOCUMENT_NODE = 9;
  document.DOCUMENT_TYPE_NODE = 10;
  document.DOCUMENT_FRAGMENT_NODE = 11;
  document.NOTATION_NODE = 12;
}

document._importNode = function(node, allChildren) {
  switch (node.nodeType) {
    case document.ELEMENT_NODE:
      var newNode = document.createElement(node »
.nodeName);
      /* does the node have any attributes to add? */
      if (node.attributes && node.attributes »
.length > 0)
        for (var i = 0; il = node.attributes.length;i < il)
          newNode.setAttribute(node.attributes[i].nodeName, 
          node.getAttribute(node.attributes[i++].nodeName));
      /* are we going after children too, and does the node have any? */
      if (allChildren && node.childNodes && node.childNodes.length > 0)
        for (var i = 0; il = node.childNodes.length; i < il)
          newNode.appendChild(document._importNode(node.childNodes[i++], allChildren));
      return newNode;
      break;
    case document.TEXT_NODE:
    case document.CDATA_SECTION_NODE:
    case document.COMMENT_NODE:
      return document.createTextNode(node.nodeValue);
      break;
  }
};

Here it is in use:

var newNode = null, importedNode = null;

newNode = xhrResponse.responseXML.getElementsByTagName('title')[0].childNodes[0];
if (newNode.nodeType != document.ELEMENT_NODE)
  newNode = newNode.nextSibling;
if (newNode) {
  importedNode = document._importNode(newNode, true);
  document.getElementById('divTitleContainer').appendChild(importedNode);
  if (!document.importNode)
    document.getElementById('divTitleContainer').innerHTML = document.getElementById('divTitleContainer').innerHTML;
}
Jonathan Fingland
  • 56,385
  • 11
  • 85
  • 79
  • 1
    This is a good general approach, but you'll want to `document.createComment` in response to a `COMMENT_NODE`; turning it into a text node probably isn't a good idea. There are also many problems with using `getAttribute`/`setAttribute` on HTML elements in IE, unfortunately; if you're cloning forms the `name` may be a problem, and `onX` attributes and inline `style`​s aren't going to work in a useful way (best avoid them). Also any ` – bobince Nov 28 '09 at 01:47
  • @bobince: excellent point about the comment nodes. get/setAttribute can be a problem on IE6 sometimes, though, I haven't noticed significant problems on IE7+ with that particular pair of functions (lots to complain about otherwise, though). – Jonathan Fingland Nov 28 '09 at 05:18
  • 1
    To also support namespaced attributes, use setAttributeNS and getAttributeNS instead of setAttribute and getAttribute. – Martijn van de Rijdt Oct 17 '16 at 23:15
-1

For a lighter-weight solution (provided you don't mind adding the dependency), you could always use jQuery:

$(dom_to_import_into).find('element-to-import-into').append($(dom_to_import).clone());

This will add dom_to_import at the end of 'element-to-import-into'.

Ryan
  • 496
  • 6
  • 13
  • MAY NOT WORK in IE. Depends what you are trying to do. I suspect the original poster is using importNode because s/he is copying from an external document (e.g. iframe or window.open). As such, using jQuery's append() will still fail on IE. HierarchyRequestError. – joedotnot Dec 12 '16 at 07:47