getElementsByTagName () textNodes के लिए बराबर


79

क्या किसी textNodeदस्तावेज़ के भीतर सभी वस्तुओं का संग्रह प्राप्त करने का कोई तरीका है ?

getElementsByTagName()तत्वों के लिए महान काम करता है, लेकिन textNodeतत्व नहीं हैं।

अद्यतन: मुझे लगता है कि यह डोम चलने से पूरा किया जा सकता है - जैसा कि नीचे दिए गए कई सुझाव हैं। मुझे पता है कि डॉम-वॉकर फ़ंक्शन कैसे लिखना है जो दस्तावेज़ में प्रत्येक नोड को देखता है। मुझे उम्मीद थी कि ऐसा करने के लिए कुछ ब्राउज़र-देशी तरीका था। आखिरकार यह थोड़ा अजीब है कि मैं <input>एक ही बिल्ट-इन कॉल के साथ सभी एस प्राप्त कर सकता हूं , लेकिन सभी textNodeएस नहीं ।

जवाबों:


117

अपडेट :

मैंने 1000 से अधिक इन 6 तरीकों में से प्रत्येक के लिए कुछ बुनियादी प्रदर्शन परीक्षणों की रूपरेखा तैयार की है। getElementsByTagNameसबसे तेज़ है, लेकिन यह एक आधा-गधा काम करता है, क्योंकि यह सभी तत्वों का चयन नहीं करता है, लेकिन केवल एक विशेष प्रकार का टैग (मुझे लगता है p) और आँख बंद करके मानता है कि इसका पहला पाठ एक पाठ तत्व है। यह थोड़ा त्रुटिपूर्ण हो सकता है लेकिन इसके प्रदर्शन उद्देश्य के लिए और इसके प्रदर्शन की तुलना करने के लिए TreeWalker। परिणाम देखने के लिए अपने आप को jsfiddle पर परीक्षण चलाएं

  1. ट्रीवल्कर का उपयोग करना
  2. कस्टम Iterative Traversal
  3. कस्टम पुनरावर्ती Traversal
  4. Xpath क्वेरी
  5. querySelectorAll
  6. getElementsByTagName

आइए एक पल के लिए मान लें कि एक विधि है जो आपको Textमूल रूप से सभी नोड्स प्राप्त करने की अनुमति देती है । आपको अभी भी प्रत्येक परिणामी टेक्स्ट नोड को पार करना होगा और node.nodeValueवास्तविक पाठ प्राप्त करने के लिए कॉल करना होगा जैसा कि आप किसी भी डोम नोड के साथ करेंगे। तो प्रदर्शन का मुद्दा पाठ नोड्स के माध्यम से पुनरावृत्ति के साथ नहीं है, लेकिन उन सभी नोड्स के माध्यम से पुनरावृत्ति करना जो पाठ नहीं हैं और उनके प्रकार की जांच कर रहे हैं। मैं तर्क दूंगा (परिणामों के आधार पर) जो TreeWalkerजितनी तेजी से प्रदर्शन करता है getElementsByTagName, अगर तेजी से नहीं (यहां तक ​​कि getElementsByTagName के साथ विकलांग खेलते हुए)।

प्रत्येक परीक्षण 1000 बार दौड़ा।

विधि कुल एमएस औसत एमएस
--------------------------------------------------------------
दस्तावेज़। फ्रीवैलर 301 0.301
Iterative Traverser 769 0.769
पुनरावर्ती ट्रैवर्स 7352 7.352
XPath क्वेरी 1849 1.849
querySelectorAll 1725 1.725
getElementsByTagName 212 0.212

प्रत्येक विधि के लिए स्रोत:

ट्रीवल्कर

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

Iterative ट्री ट्रैवर्सल

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


1
मैंने ऊपर दिए गए प्रत्येक विधि के लिए अलग-अलग ब्राउज़र में मिश्रित परिणाम प्राप्त किए हैं - ऊपर दिए गए ये परिणाम क्रोम के लिए हैं। फ़ायरफ़ॉक्स और सफारी बहुत अलग तरह से व्यवहार करते हैं। मेरे पास दुर्भाग्य से IE का उपयोग नहीं है, लेकिन आप यह देखने के लिए IE पर अपने आप को परीक्षण कर सकते हैं कि क्या यह काम करता है। जैसा कि ब्राउज़र ऑप्टिमाइज़ेशन के लिए है, मैं तब तक प्रत्येक ब्राउज़र के लिए एक अलग विधि चुनने के बारे में चिंता नहीं करूँगा जब तक कि दसियों मिलीसेकंड के क्रम में अंतर न हों या शायद कम सैकड़ों।
अनुराग

1
यह वास्तव में उपयोगी उत्तर है, लेकिन सावधान रहें कि विभिन्न विधियां बहुत अलग चीजें लौटाती हैं। यदि उनमें से अपने माता-पिता की पहली संतान है तो उनमें से कई को केवल पाठ नोड्स मिलते हैं। उनमें से कुछ केवल पाठ प्राप्त कर सकते हैं, जबकि अन्य मामूली संशोधनों के साथ वास्तविक पाठ नोड्स वापस कर सकते हैं। Iterative Tree Traversal में एक त्रुटि है जो इसके प्रदर्शन को प्रभावित कर सकती है। बदलें node.nodeType = 3करने के लिएnode.nodeType == 3
theazureshadow

@theazureshadow - शानदार =बग को इंगित करने के लिए धन्यवाद । मैंने तय किया है कि, और xpath संस्करण केवल Textवस्तुओं को वापस कर रहा था , न कि वास्तविक स्ट्रिंग इसमें निहित था जैसे अन्य तरीके कर रहे थे। वह विधि जो केवल पहले बच्चे का पाठ हो रही है वह जानबूझकर गलत है, और मैंने शुरुआत में इसका उल्लेख किया है। मैं परीक्षण फिर से चलाऊंगा, और अपडेट किए गए परिणामों को यहां पोस्ट करूंगा। सभी परीक्षण (getElementsByTagName और xpath को छोड़कर) एक ही नंबर के टेक्स्ट नोड्स वापस कर रहे हैं। XPath दूसरों की तुलना में 20 अधिक नोड्स के बारे में रिपोर्ट कर रहा है जिसे मैं अभी के लिए अनदेखा करूंगा।
अनुराग

6
मैंने परीक्षणों को समकक्ष बनाया है और एक jsPerf बनाया है: jsperf.com/text-node-traversal
टिम डाउन

1
अच्छा काम @TimDown - कि विकलांग परीक्षण एक लंबे समय के लिए एक आंख में खराश था :) आपको इसे एक उत्तर के रूप में जोड़ना चाहिए ..
अनुराग

5

यहां 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;
}

4

मुझे पता है कि आपने विशेष रूप से एक संग्रह के लिए कहा था, लेकिन अगर आपका मतलब सिर्फ अनौपचारिक रूप से है और परवाह नहीं है कि वे सभी एक साथ एक बड़ी स्ट्रिंग में शामिल हो गए हैं, तो आप उपयोग कर सकते हैं:

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

... पहला आइटम DOM3 मानक दृष्टिकोण के साथ। हालाँकि, नोट जो innerTextइसे लागू करने वाली स्क्रिप्ट (या टैग टैग सामग्री) को बाहर करने के लिए प्रकट होता है जो इसे (कम से कम IE और क्रोम) जबकि textContentउन्हें (फ़ायरफ़ॉक्स और क्रोम में) शामिल करता है।


1
धन्यवाद - यह वह नहीं है जो मैं चाहता था। मेरी ज़रूरत उन्हें डोम ऑब्जेक्ट्स (जैसे उनके माता-पिता को खोजने आदि) के रूप में इन-प्लेस का निरीक्षण करने में सक्षम होने के लिए
बुलाती है

1
 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

यहाँ एक विकल्प है जो थोड़ा अधिक मुहावरेदार है और (उम्मीद है) समझने में आसान है।

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

0
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

के बाद createTreeWalkerपदावनत आप उपयोग कर सकते हैं

  /**
   * Get all text nodes under an element
   * @param {!Element} el
   * @return {Array<!Node>}
   */
  function getTextNodes(el) {
    const iterator = document.createNodeIterator(el, NodeFilter.SHOW_TEXT);
    const textNodes = [];
    let currentTextNode;
    while ((currentTextNode = iterator.nextNode())) {
      textNodes.push(currentTextNode);
    }
    return textNodes;
  }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.