Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Faster way of replacing text in all dom elements?

I'm trying to replace all text in between tags and I want to know the fastest way of doing so.

An example would be trying to replace all text with the arbitrary string helloWorld, so that this:

<div>
    <div>
        RandomText1
        <div>
            RandomText2
        </div>
    </div>
</div>

Becomes this:

<div>
    <div>
        helloWorld
        <div>
            helloWorld
        </div>
    </div>
</div>

My current approach would be :

  • Do Depth-first search (DFS) on DOM
  • For each element parse and determine which part is text and which part is an element.
  • For the part that is text replace it.

This to me would be really slow, especially trying to do this for a large document and having to repeat the process many times. Is there a faster way?

like image 373
Darkzuh Avatar asked Feb 04 '17 13:02

Darkzuh


2 Answers

You don't need to parse each element to find text nodes, you can just recursively traverse childNodes property of an element

var newText = 'hello world';
function replaceTextNodes(node) {
  node.childNodes.forEach(function(el) {
    if (el.nodeType === 3) {  // If this is a text node, replace the text
      if (el.nodeValue.trim() !== "") { // Ignore this node it it an empty text node
        el.nodeValue = newText;
      }
    } else { // Else recurse on this node
      replaceTextNodes(el);
    }
  });
}

var onClick = replaceTextNodes.bind(null, document.querySelector('#container'));
document.querySelector('#replace').addEventListener('click', onClick);
<div id='container'>
  <div>
    RandomText1
    <div>
      RandomText2
      <ul>
        <li>RandomText3</li>
      </ul>
    </div>
  </div>
</div>
<button id="replace">Replace</button>
like image 185
jetpackpony Avatar answered Oct 27 '22 22:10

jetpackpony


Use TreeWalker object as the most fast tool for DOM traversal.
A TreeWalker can be created using the Document.createTreeWalker() method.

function replaceAllText(newText) {
    var walker = document.createTreeWalker(
        document.body,  // root node
        NodeFilter.SHOW_TEXT,  // filtering only text nodes
        null,
        false
    );
    
    while (walker.nextNode()) {
        if (walker.currentNode.nodeValue.trim())  // if it's not empty(whitespaced) node
          walker.currentNode.nodeValue = newText;
    }
}

replaceAllText("helloWorld");
<div>
    <div>
        RandomText1
        <div>
            RandomText2
        </div>
    </div>
</div>

https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker

Performance test demonstration

like image 22
RomanPerekhrest Avatar answered Oct 28 '22 00:10

RomanPerekhrest