web-dev-qa-db-fra.com

getElementsByTagName () équivalent pour textNodes

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 textNodes 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 textNodes.

67
levik

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.

  1. Utiliser un TreeWalker
  2. Traversée Itérative Personnalisée
  3. Traversée récursive personnalisée
  4. Requête Xpath
  5. querySelectorAll
  6. getElementsByTagName

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

102
Anurag

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).

4
Brett Zamir

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;
}
2
bfred.it
 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.

1
kennebec

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
        }
    }
}
1
jtschoonhoven
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)
0
Mankament Gra