Existe-t-il un moyen de récupérer la collection de tous les objets textNode
dans un document?
getElementsByTagName()
fonctionne très bien pour les éléments, mais textNode
s ne sont pas des éléments.
Mise à jour: Je réalise que cela peut être accompli en marchant dans le DOM - comme le suggèrent beaucoup ci-dessous. Je sais comment écrire une fonction DOM-walker qui examine tous les nœuds du document. J'espérais qu'il y avait un moyen natif de navigateur pour le faire. Après tout, il est un peu étrange que je puisse obtenir tous les <input>
s avec un seul appel intégré, mais pas tous les textNode
s.
Mettre à jour:
J'ai présenté quelques tests de performance de base pour chacune de ces 6 méthodes sur plus de 1000 exécutions. getElementsByTagName
est le plus rapide, mais il effectue un travail à moitié assigné, car il ne sélectionne pas tous les éléments, mais un seul type de balise (je pense que p
) et suppose aveuglément que son firstChild est un élément de texte. Il pourrait être peu imparfait, mais il est là à des fins de démonstration et en comparant sa performance à TreeWalker
. Faites vous-même les tests sur jsfiddle pour voir les résultats.
Supposons un instant qu'il existe une méthode permettant d'obtenir tous les nœuds Text
de manière native. Vous devez toujours traverser chaque nœud de texte résultant et appeler node.nodeValue
pour obtenir le texte réel comme vous le feriez avec n'importe quel nœud DOM. Le problème de performances ne consiste donc pas à parcourir les nœuds de texte, mais à parcourir tous les nœuds qui ne sont pas du texte et à en vérifier le type. Je dirais (sur la base des résultats) que TreeWalker
fonctionne aussi vite que getElementsByTagName
, sinon plus vite (même avec getElementsByTagName jouant avec un handicap).
Répétée chaque test 1000 fois . Méthode Total ms Moyenne ms --------------------------- ----------------------- document.TreeWalker 301 0.301 Traverseur itératif 769 0.769 Traverser récursif 7352 7.352 Requête XPath 1849 1,849 QuerySelectorAll 1725 1.725 GetElementsByTagName 212 0.212
Source pour chaque méthode:
TreeWalker
function nativeTreeWalker() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.Push(node.nodeValue);
}
}
Traversée d'arbre récursive
function customRecursiveTreeWalker() {
var result = [];
(function findTextNodes(current) {
for(var i = 0; i < current.childNodes.length; i++) {
var child = current.childNodes[i];
if(child.nodeType == 3) {
result.Push(child.nodeValue);
}
else {
findTextNodes(child);
}
}
})(document.body);
}
Traversée itérative d'arbres
function customIterativeTreeWalker() {
var result = [];
var root = document.body;
var node = root.childNodes[0];
while(node != null) {
if(node.nodeType == 3) { /* Fixed a bug here. Thanks @theazureshadow */
result.Push(node.nodeValue);
}
if(node.hasChildNodes()) {
node = node.firstChild;
}
else {
while(node.nextSibling == null && node != root) {
node = node.parentNode;
}
node = node.nextSibling;
}
}
}
querySelectorAll
function nativeSelector() {
var elements = document.querySelectorAll("body, body *"); /* Fixed a bug here. Thanks @theazureshadow */
var results = [];
var child;
for(var i = 0; i < elements.length; i++) {
child = elements[i].childNodes[0];
if(elements[i].hasChildNodes() && child.nodeType == 3) {
results.Push(child.nodeValue);
}
}
}
getElementsByTagName (handicap)
function getElementsByTagName() {
var elements = document.getElementsByTagName("p");
var results = [];
for(var i = 0; i < elements.length; i++) {
results.Push(elements[i].childNodes[0].nodeValue);
}
}
XPath
function xpathSelector() {
var xpathResult = document.evaluate(
"//*/text()",
document,
null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE,
null
);
var results = [], res;
while(res = xpathResult.iterateNext()) {
results.Push(res.nodeValue); /* Fixed a bug here. Thanks @theazureshadow */
}
}
Cette discussion peut également vous être utile - http://bytes.com/topic/javascript/answers/153239-how-do-i-get-elements-text-node
Je sais que vous avez spécifiquement demandé une collection, mais si vous vouliez simplement dire cela de manière informelle et que vous ne vouliez pas qu'ils soient tous unis dans une grande chaîne, vous pouvez utiliser:
var allTextAsString = document.documentElement.textContent || document.documentElement.innerText;
... avec le premier élément étant l'approche standard DOM3. Notez cependant que innerText
semble exclure le contenu des balises de script ou de style dans les implémentations qui le prennent en charge (au moins IE et Chrome) alors que textContent
les inclut (dans Firefox et Chrome).
Voici une version Iterator
moderne de la méthode TreeWalker la plus rapide:
function getTextNodesIterator(el) { // Returns an iterable TreeWalker
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
const next = () => {
const value = walker.nextNode();
return {
value,
done: !value
};
};
walker[Symbol.iterator] = () => ({next});
return walker;
}
Usage:
for (const textNode of getTextNodesIterator(document.body)) {
console.log(textNode)
}
Mais la boucle risque de rester bloquée si vous déplacez les nœuds pendant la boucle.
C'est plus sûr:
function getTextNodes(el) { // Returns an array of Text nodes
const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
const nodes = [];
while (walker.nextNode()) {
nodes.Push(walker.currentNode);
}
return nodes;
}
document.deepText= function(hoo, fun){
var A= [], tem;
if(hoo){
hoo= hoo.firstChild;
while(hoo!= null){
if(hoo.nodeType== 3){
if(typeof fun== 'function'){
tem= fun(hoo);
if(tem!= undefined) A[A.length]= tem;
}
else A[A.length]= hoo;
}
else A= A.concat(document.deepText(hoo, fun));
hoo= hoo.nextSibling;
}
}
return A;
}
/*Vous pouvez renvoyer un tableau de tous les nœuds de texte descendants d’un élément parent, .__ ou vous pouvez lui transmettre une fonction et effectuer une opération (recherche, remplacement ou autre) Au texte en place.
Cet exemple renvoie le texte des noeuds textuels autres que des espaces blancs dans le corps:
var A= document.deepText(document.body, function(t){
var tem= t.data;
return /\S/.test(tem)? tem: undefined;
});
alert(A.join('\n'))
* /
Pratique pour rechercher et remplacer, surligner, etc.
Voici une alternative un peu plus idiomatique et (espérons-le) plus facile à comprendre.
function getText(node) {
// recurse into each child node
if (node.hasChildNodes()) {
node.childNodes.forEach(getText);
}
// get content of each non-empty text node
else if (node.nodeType === Node.TEXT_NODE) {
const text = node.textContent.trim();
if (text) {
console.log(text); // do something
}
}
}
var el1 = document.childNodes[0]
function get(node,ob)
{
ob = ob || {};
if(node.childElementCount)
{
ob[node.nodeName] = {}
ob[node.nodeName]["text"] = [];
for(var x = 0; x < node.childNodes.length;x++)
{
if(node.childNodes[x].nodeType == 3)
{
var txt = node.childNodes[x].nodeValue;
ob[node.nodeName]["text"].Push(txt)
continue
}
get(node.childNodes[x],ob[node.nodeName])
};
}
else
{
ob[node.nodeName] = (node.childNodes[0] == undefined ? null :node.childNodes[0].nodeValue )
}
return ob
}
var o = get(el1)
console.log(o)