web-dev-qa-db-ja.com

getElementsByTagName()と同等のtextNodes

ドキュメント内のすべてのtextNodeオブジェクトのコレクションを取得する方法はありますか?

getElementsByTagName()はElementsには最適ですが、textNodesはElementsではありません。

pdate:これは、DOMをウォークすることで実現できることを理解しています。文書内のすべてのノードを調べるDOM-walker関数を作成する方法を知っています。私はそれを行うためのいくつかのブラウザネイティブの方法があることを望んでいました。結局のところ、単一の組み込み呼び出しですべての<input>sを取得できるが、すべてのtextNodesを取得できないのは少し奇妙です。

74
levik

更新

これらの6つの方法のそれぞれについて、1000回以上の実行でいくつかの基本的なパフォーマンステストを概説しました。 getElementsByTagNameは最速ですが、すべての要素を選択するのではなく、特定の1つのタイプのタグのみ(pだと思います)であり、firstChildがテキスト要素。少し欠陥があるかもしれませんが、デモ目的であり、そのパフォーマンスをTreeWalkerと比較しています。 jsfiddleで自分でテストを実行 結果を確認します。

  1. TreeWalkerの使用
  2. カスタム反復トラバーサル
  3. カスタム再帰トラバーサル
  4. Xpathクエリ
  5. querySelectorAll
  6. getElementsByTagName

しばらくの間、すべてのTextノードをネイティブで取得できるメソッドがあると仮定します。結果の各テキストノードをトラバースし、node.nodeValueを呼び出して、任意のDOMノードの場合と同じように実際のテキストを取得する必要があります。したがって、パフォーマンスの問題は、テキストノードを反復処理することではなく、テキストではないすべてのノードを反復処理し、そのタイプをチェックすることです。 (結果に基づいて)TreeWalkerのパフォーマンスはgetElementsByTagNameと同じぐらい速く、たとえハンディキャップのあるgetElementsByTagNameを使用していても、速くないと主張します。

各テストを1000回実行しました。
 
メソッドの合計ms平均ms 
 ------------------- ------------------------------- 
 document.TreeWalker 301 0.301 
反復トラバーサー769 0.769 
再帰トラバーサー7352 7.352 
 XPathクエリ1849 1.849 
 querySelectorAll 1725 1.725 
 getElementsByTagName 212 0.212 

各メソッドのソース:

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

再帰的ツリートラバーサル

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

反復ツリートラバーサル

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(ハンディキャップ)

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 */
    }
}

また、このディスカッションが役立つ場合があります- http://bytes.com/topic/javascript/answers/153239-how-do-i-get-elements-text-node

103
Anurag

コレクションを具体的に要求したことは知っていますが、それを非公式に意味するだけで、すべてが1つの大きな文字列に結合されているかどうかを気にしない場合は、次のように使用できます。

var allTextAsString = document.documentElement.textContent || document.documentElement.innerText;

...最初の項目はDOM3標準アプローチです。ただし、innerTextは、それをサポートする実装(少なくともIEおよびChrome))でスクリプトまたはスタイルタグのコンテンツを除外しているように見えますが、textContentはそれらを含みます(Firefoxの場合)およびChrome)。

4
Brett Zamir

これが最速のTreeWalkerメソッドの最新のIteratorバージョンです。

function getTextNodesIterator(el) { // Returns an iterable TreeWalker
    const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
    walker[Symbol.iterator] = () => ({
        next() {
            const value = walker.nextNode();
            return {value, done: !value};
        }
    });
    return walker;
}

使用法:

for (const textNode of getTextNodesIterator(document.body)) {
    console.log(textNode)
}

安全なバージョン

ループ中にノードを移動すると、イテレータを直接使用するとスタックする可能性があります。これはより安全です、それは配列を返します:

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
fregante
 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;
    }

/ *いくつかの親要素のすべての子孫テキストノードの配列を返すことができます。または、それにいくつかの関数を渡して、テキストに対して何か(検索または置換など)を実行することができます。

この例では、本文内の空白以外のテキストノードのテキストを返します。

var A= document.deepText(document.body, function(t){
    var tem= t.data;
    return /\S/.test(tem)? tem: undefined;
});
alert(A.join('\n'))

* /

検索、置換、ハイライトなどに便利

1
kennebec

これはもう少し慣用的で、(うまくいけば)理解しやすい代替案です。

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