2012-07-17 8 views
7

Voglio sostituire una stringa particolare nel (il testo di) tutti gli elementi discendenti di un dato elemento.Sostituisci tutta l'ocurrance di una stringa in un elemento

innerHTML non può essere utilizzato poiché questa sequenza può apparire negli attributi. Ho provato ad usare XPath, ma sembra che l'interfaccia sia essenzialmente di sola lettura. Poiché questo è limitato a un elemento, non è possibile utilizzare funzioni come document.getElementsByTagName.

Qualcuno potrebbe suggerire un modo per farlo? Qualsiasi metodo jQuery o DOM puro è accettabile.

Edit:

Alcune delle risposte stanno suggerendo il problema che stavo cercando di risolvere: la modifica del testo direttamente su un elemento causerà tutti i nodi figli non testuale per essere rimosso.

Quindi il problema dipende essenzialmente da come selezionare in modo efficiente tutti i nodi di testo in un albero. In XPath, puoi farlo facilmente come //text(), ma l'attuale interfaccia XPath non ti permette di cambiare questi nodi di testo.

Un modo per farlo è con ricorsione come mostrato nello answer di Bergi. Un altro way utilizza il selettore find('*') di jQuery, ma questo è un po 'più costoso. Sto ancora aspettando di vedere se ci sono soluzioni migliori.

+0

[selettori di jQuery] (http://api.jquery.com/category/selectors/) ti consente di attraversare e modificare dom, accedere ai discendenti e ai fratelli di un elemento. E altro ancora. –

+0

@ADC, sfortunatamente non c'è niente come il selettore textath di XPath .... –

risposta

4

basta usare un semplice selfmade DOM-iteratore, che cammina in modo ricorsivo su tutti i nodi:

(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 
+1

+1 per una soluzione non jQuery. Fa un cambiamento! – Matt

0

Siamo spiacenti, appena ricevuto io stesso:

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

ho usato toUpperCase() qui per rendere il risultato più evidente, ma qualsiasi operazione String sarebbe valido lì.

+1

Suppongo che l'oggetto 'Text' non esista in IE8 e inferiore. Meglio usare 'this.nodeType === 3'. – duri

+0

Questo * break * dove 'Text' non è un riferimento a un oggetto, come in MSHTML <8 (IE <8). Lo stesso vale per la proprietà 'data'. Si romperà anche dove 'instanceof' non è supportato, sebbene tali implementazioni siano rare al giorno d'oggi, e jQuery non è in grado di supportarle in primo luogo. Dovresti aggiungere test di funzionalità e seguire i consigli di duri. – PointedEars

0

utilizzando jQuery:

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

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

Se si preferisce per la ricerca in tutti i bambini invece di solo i bambini immediati, utilizzare .find() invece.

http://jsfiddle.net/ExwDx/

Edit: La documentazione per children, each, text e find.

+0

Questo è ciò a cui stavo lavorando prima di pubblicare questa domanda. Il problema è che se l'elemento ha figli non di testo, saranno rimossi come risultato della chiamata a 'text()'. Ovviamente questo non è accettabile. –

+0

includerà i nodi di testo e non rimuoverà i bambini non di testo. – jbabey

+0

@jbabey: hai ragione, rimosso il mio commento. Sapete da che versione '.children()' restituisce anche TextNode? – jAndy

1

Una soluzione potrebbe essere quella di navigare attraverso tutti i nodi disponibili (TextNode inclusi) e applicare un motivo regexp sui risultati. Per afferrare TextNodes, è necessario invocare jQuerys .contents(). Per esempio:

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')); 
}); 

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

Riferimento: .contents()

+0

Penso che l'assegnazione a textContent rimuoverà tutti i nodi non di testo in modo simile alla chiamata a 'text()' di jQuery come suggerito da jbabey. –

+0

@ billc.cn: giusto, ho aggiornato il codice e l'esempio, la ricorsione dovrebbe fare il lavoro lì. – jAndy

+0

Questo codice è jQuery eccessivamente complicato e misto con metodi DOM nativi. Perché, ad esempio, si applica String.trim sul nodoValues ​​prima di replace()? – Bergi

Problemi correlati