简体   繁体   中英

Node.normalize() crashes in IE6

I am doing some manipulation of TextNodes in javascript, and I (unfortunately) need to support IE6. Node.normalize() is crashing, and I need to work around this. My first inclination is to just re-implement it using other DOM methods. How would I implement this?

The following version is shorter and more efficient than others posted here. The improvements are:

  • No repeated calls to node.childNodes and node.childNodes.length
  • No creation of extra text nodes; instead, for each merge, keep the first existing text node and use its appendData() method
  • Shorter

The code:

function normalize(node) {
    var child = node.firstChild, nextChild;
    while (child) {
        if (child.nodeType == 3) {
            while ((nextChild = child.nextSibling) && nextChild.nodeType == 3) {
                child.appendData(nextChild.data);
                node.removeChild(nextChild);
            }
        } else {
            normalize(child);
        }
        child = child.nextSibling;
    }
}

The solution above was running very slow and crashing Firefox for me. So I optimized it a bit and it's working great now (the main issue was with repeatedly referencing the HTML collection object node.childNodes).

Thanks for the great starting point, but I figured this was worth posting:


function myNormalize(node) {
    for (var i=0, children = node.childNodes, nodeCount = children.length; i<nodeCount; i++) {
        var child = children[i];
        if (child.nodeType == 1) {
            myNormalize(child);
            continue;
        }
        if (child.nodeType != 3) { continue; }
        var next = child.nextSibling;
        if (next == null || next.nodeType != 3) { continue; }
        var combined_text = child.nodeValue + next.nodeValue;
        new_node = node.ownerDocument.createTextNode(combined_text);
        node.insertBefore(new_node, child);
        node.removeChild(child);
        node.removeChild(next);
        i--;
        nodeCount--;
    }
}

You'd need to recursively look through all of the child nodes of the current node. When considering a node, you'd delete any empty text nodes and combine any adjacent text nodes.

 function myNormalize( node )
     for each child node of node do
         if child is not text
            normalize(child)
         else
            if child node is empty
               delete
               continue
            else 
                sibling = next node
                while sibling exists and sibling is a text node
                    if sibling is empty
                       delete sibling
                    else
                       combine sibling with child
                    get next sibling
                end
            end
        end
    end
end

I think that the solution provided above is not entirely correct. FWIW, here is a working normalize function plus a glue function that uses the native normalize if it's available:

function _myNormalizeNode(node) {
if (! node) {
    return;
}

var ELEMENT_NODE = 1;
var TEXT_NODE = 3;
var child = node.firstChild;
while (child) {
    if (child.nodeType == ELEMENT_NODE) {
        this._myNormalizeNode(child);
    }
    else if (child.nodeType == TEXT_NODE) { 
        var next;
        while ((next = child.nextSibling) && next.nodeType == TEXT_NODE) { 
            var value = next.nodeValue;
            if (value != null && value.length) {
                child.nodeValue = child.nodeValue + value;
            }
            node.removeChild(next);
        }
    }
    child = child.nextSibling;
}

}

function  _normalizeNode(node) {
if (! node) {
    return;
}
if (typeof node.normalize == "function") {
    return node.normalize();
}
return _myNormalizeNode(node);

}

based on tvanfosson's pseudocode, here's what I came up with in javascript:

var ELEMENT_NODE = 1;
var TEXT_NODE = 3;
function normalize(node) {
    for (i=0; i<node.childNodes.length; i++) {
        var child = node.childNodes[i];
        if (child.nodeType == ELEMENT_NODE) {
            normalize(child);
            continue;
        }
        if (child.nodeType != TEXT_NODE) { continue; }
        var next = child.nextSibling;
        if (next == null || next.nodeType != TEXT_NODE) { continue; }
        var combined_text = child.nodeValue + next.nodeValue;
        new_node = node.ownerDocument.createTextNode(combined_text);
        node.insertBefore(new_node, child);
        node.removeChild(child);
        node.removeChild(next);
        i -= 1;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM