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:
node.childNodes
and node.childNodes.length
appendData()
method 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.