Search code examples
javascriptdomreplacetraversal

Traverse and Update DOM


I have a below sample html page. I want to traverse DOM using plain JavaScript and replace the word www.demourl.com with www.betaurl.com.

<!doctype html>
<html>
    <head>
      <meta charset="utf-8">
      <title>DOM replace</title>
      <script>
        function process(node){
            var nodes = node.childNodes;
            for (var i = 0; i <nodes.length; i++){
                if(!nodes[i]){
                    continue;
                } else {
                    if (nodes[i].data.indexOf("www.demourl.com") != -1) {
                        nodes[i].data = nodes[i].data.replace(/www.demourl.com/g, 'www.betaurl.com')
                    }
                }

                if(nodes[i].childNodes.length > 0){
                    loop(nodes[i]);
                }
            }
        }
        window.onload = function() {
            process(document);
        }         
      </script>
    </head>
    <body>
        <div id="main">
            <div id="first">www.demourl.com</div>
            <div id="second">
                <p>www.demourl.com</p>
            </div>
            <a href="http://www.demourl.com/demo">View Demo</a>
        </div>
        <div id="container">
            <table>
                <tr>
                    <td>
                        <img src="http://www.demourl.com/assets/">
                    </td>
                </tr>
            </table>
        </div>
    </body>
</html>

for some reason URL is not being replaced on the page. What changes need to be made in the process function?


Solution

  • A few issues:

    • Pass an argument to the initial call
    • Recursive call should be to process, not loop
    • Use .nodeValue not .data
    • Check whether the node is a text node, e.g. by checking if nodeValue exists (which is the case also for comment nodes...)
    • The literal dot needs to be escaped in a regex.
    • For replacing also in attributes, you need extra code to iterate those.

    Corrected:

    function process(node){
        var nodes = node.childNodes;
        for (var i = 0; i <nodes.length; i++){
            //console.log(nodes[i]);
            if(!nodes[i]) continue;
             // *** it's not data, but nodeValue. Add a check if property exists
            if (nodes[i].nodeValue && nodes[i].nodeValue.indexOf("www.demourl.com") != -1) {
                // regex with escaped dot:
                nodes[i].nodeValue = nodes[i].nodeValue.replace(/www\.demourl\.com/g, 'www.betaurl.com')
            }
            // *** additional code to do same for attributes
            var attr = nodes[i].attributes;
            if (attr) {
                for (var j = 0; j < attr.length; j++) {
                    if (attr[j].value.indexOf("www.demourl.com") != -1) {
                        attr[j].value = attr[j].value.replace(/www\.demourl\.com/g, 'www.betaurl.com')
                    }
                }
            }
            if(nodes[i].childNodes.length > 0){
                process(nodes[i]); // *** it's not loop
            }
        }
    }
    window.onload = function() {
        process(document.body); // *** pass argument
    }         
    <div id="main">
        <div id="first">www.demourl.com</div>
        <div id="second">
            <p>www.demourl.com</p>
        </div>
        <a href="http://www.demourl.com/demo">View Demo</a>
    </div>
    <div id="container">
        <table>
            <tr>
                <td>
                    <img src="http://www.demourl.com/assets/">
                </td>
            </tr>
        </table>
    </div>