2012-07-17 11 views
7

Ich möchte eine bestimmte Zeichenfolge in (der Text von) alle untergeordneten Elemente eines bestimmten Elements ersetzen.Ersetzen Sie alle ourrance einer Zeichenfolge in einem Element

innerHTML kann nicht verwendet werden, da diese Sequenz in Attributen erscheinen kann. Ich habe versucht, XPath zu verwenden, aber es scheint, dass die Schnittstelle im Wesentlichen schreibgeschützt ist. Da dies auf ein Element beschränkt ist, können Funktionen wie document.getElementsByTagName ebenfalls nicht verwendet werden.

Kann irgendjemand irgendeinen Weg vorschlagen, dies zu tun? Jede jQuery- oder reine DOM-Methode ist akzeptabel.

Edit:

Einige Antworten sind darauf hindeutet, das Problem, das ich habe versucht, um zu arbeiten: an einem Element den Text direkt ändern verursachen alle Nicht-Text Kind-Knoten entfernt werden.

Das Problem besteht also im Wesentlichen darin, wie alle Textknoten in einem Baum effizient ausgewählt werden können. In XPath können Sie es einfach als //text() ausführen, aber die aktuelle XPath-Schnittstelle erlaubt es Ihnen nicht, diese Textknoten zu ändern.

Ein Weg, dies zu tun, ist durch Rekursion wie in der answer von Bergi gezeigt. Ein weiterer way ist die Verwendung der find('*') Selektor von jQuery, aber das ist ein bisschen teurer. Ich warte immer noch darauf, ob es bessere Lösungen gibt.

+0

[jQuery Selektoren] (http://api.jquery.com/category/selectors/) können Sie das dom durchlaufen und ändern, auf die Nachkommen und die Geschwister eines Elements zugreifen. Und vieles mehr. –

+0

@ADC, leider gibt es nichts wie XPath Text() Selektor .... –

Antwort

4

nur einen einfachen Eigenbau DOM-Iterator verwenden, die rekursiv über alle Knoten geht:

(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 für eine Nicht-jQuery-Lösung. Macht eine Veränderung! – Matt

0

Sorry, hätte es nur mich:

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

I verwendet toUpperCase (hier) das Ergebnis deutlicher zu machen, aber jeder String Betrieb dort gültig sein würde.

+1

Ich denke, 'Text' Objekt existiert nicht in IE8 und niedriger. Besser verwenden Sie 'this.nodeType === 3'. – duri

+0

Dies wird * break * wobei 'Text' keine Referenz auf ein Objekt ist, wie in MSHTML <8 (IE <8). Gleiches gilt für die Eigenschaft 'data'. Es bricht auch dort ab, wo 'instanceof' nicht unterstützt wird, obwohl diese Implementierungen heutzutage selten sind und jQuery sie wahrscheinlich gar nicht erst unterstützen wird. Sie sollten Feature-Tests hinzufügen und den Anweisungen von Duri folgen. – PointedEars

0

Mit jQuery:

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

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

Wenn Sie es vorziehen, durch alle Kinder statt nur unmittelbaren Kinder zu suchen, verwenden Sie .find() statt.

http://jsfiddle.net/ExwDx/

Edit: Dokumentation für children, each, text und find.

+0

Dies ist, woran ich gearbeitet habe, bevor ich diese Frage gepostet habe. Das Problem ist, wenn das Element irgendwelche Nicht-Text-Kinder hat, werden sie als Folge des Aufrufs von 'text()' entfernt. Offensichtlich ist das nicht akzeptabel. –

+0

wird es Textknoten enthalten, und es werden keine Nicht-Text-Kinder entfernt. – jbabey

+0

@jbabey: Du hast Recht, habe meinen Kommentar entfernt. Weißt du seit welcher Version '.children()' gibt auch TextNodes zurück? – jAndy

1

Eine Lösung könnte sein, durch alle verfügbaren Knoten (TextNodes enthalten) zu surfen und ein Regexp-Muster auf die Ergebnisse anzuwenden. Um auch TextNodes zu erhalten, müssen Sie jQuerys .contents() aufrufen. Zum Beispiel:

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

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

Referenz: .contents()

+0

Ich denke, die Zuweisung zu textContent entfernt alle Nicht-Text-Knoten ähnlich wie der Aufruf von jQabey 'text()', wie von jbabey vorgeschlagen. –

+0

@ billc.cn: richtig, ich habe den Code und das Beispiel aktualisiert, Rekursion sollte die Arbeit dort erledigen. – jAndy

+0

Dieser Code ist übermäßig kompliziert und gemischte jQuery mit nativen DOM-Methoden. Warum wenden Sie zum Beispiel String.trim auf die nodeValues ​​vor replace() an? – Bergi

Verwandte Themen