billc.cn
billc.cn

Reputation: 7317

Replace all the ocurrance of a string in an element

I want to replace a particular string in (the text of) all the descendant elements of a given element.

innerHTML cannot be used as this sequence can appear in attributes. I have tried using XPath, but it seems the interface is essentially read-only. Because this is limited to one element, functions like document.getElementsByTagName cannot be used either.

Could any suggest any way to do this? Any jQuery or pure DOM method is acceptable.

Edit:

Some of the answers are suggesting the problem I was trying to work around: modifying the text directly on an Element will cause all non-Text child nodes to be removed.

So the problem essentially comes down to how to efficiently select all the Text nodes in a tree. In XPath, you can easily do it as //text(), but the current XPath interface does not allow you to change these Text nodes it seems.

One way to do this is by recursion as shown in the answer by Bergi. Another way is to use the find('*') selector of jQuery, but this is a bit more expensive. Still waiting to see if there' are better solutions.

Upvotes: 7

Views: 1364

Answers (4)

jAndy
jAndy

Reputation: 236022

A solution might be to surf through all available nodes (TextNodes included) and apply a regexp pattern on the results. To grab TextNodes as well, you need to invoke jQuerys .contents(). For instance:

var search = "foo",
    replaceWith = 'bar',
    pattern = new RegExp( search, 'g' );


function searchReplace( root ) {
    $( root ).contents().each(function _repl( _, node ) {
        if( node.nodeType === 3 )
            node.nodeValue = node.nodeValue.replace( pattern, replaceWith );
        else searchReplace( node );
    });
}

$('#apply').on('click', function() {
    searchReplace( document.getElementById('rootNode') );
});

Example: http://jsfiddle.net/h8Rxu/3/

Reference: .contents()

Upvotes: 1

Bergi
Bergi

Reputation: 664548

Just use a simple selfmade DOM-iterator, which walks recursively over all nodes:

(function iterate_node(node) {
    if (node.nodeType === 3) { // Node.TEXT_NODE
        var text = node.data.replace(/any regular expression/g, "any replacement");
        if (text != node.data) // there's a Safari bug
            node.data = text;
    } else if (node.nodeType === 1) { // Node.ELEMENT_NODE
        for (var i = 0; i < node.childNodes.length; i++) {
            iterate_node(node.childNodes[i]); // run recursive on DOM
        }
    }
})(content); // any dom node

Upvotes: 4

billc.cn
billc.cn

Reputation: 7317

Sorry, just got it myself:

$('#id').find('*').each(function(){
    $.each(this.childNodes, function() {
        if (this.nodeType === 3) {
            this.data = this.data.toUpperCase();
        }
    })
})

I used toUpperCase() here to make the result more obvious, but any String operation would be valid there.

Upvotes: 0

jbabey
jbabey

Reputation: 46647

Using jQuery:

$('#parent').children().each(function () {
    var that = $(this);

    that.text(that.text().replace('test', 'foo'));
});

If you prefer to search through all children instead of just immediate children, use .find() instead.

http://jsfiddle.net/ExwDx/

Edit: Documentation for children, each, text, and find.

Upvotes: 0

Related Questions