textNodes에 해당하는 getElementsByTagName ()


79

textNode문서 내의 모든 개체 컬렉션을 가져올 수있는 방법이 있습니까?

getElementsByTagName()Elements에서는 잘 작동하지만 textNodes는 Elements가 아닙니다.

업데이트 : 아래의 많은 사람들이 제안하는대로 DOM을 걷는 것으로 이것이 가능하다는 것을 알고 있습니다. 문서의 모든 노드를 살펴 보는 DOM-walker 함수를 작성하는 방법을 알고 있습니다. 나는 그것을 할 수있는 브라우저 네이티브 방법이 있기를 바랐습니다. 결국 <input>하나의 내장 호출로 모든 s를 얻을 수 있지만 모든 textNodes를 얻을 수 있다는 것은 조금 이상합니다 .

답변:


117

업데이트 :

1,000 회 이상 6 가지 방법 각각에 대한 몇 가지 기본 성능 테스트를 설명했습니다. getElementsByTagName가장 빠르지 만 모든 요소를 ​​선택하지 않고 특정 유형의 태그 (내 생각에 p) 만 선택 하고 firstChild가 텍스트 요소 라고 맹목적으로 가정 하기 때문에 절반 수준의 작업을 수행합니다 . 결함이 거의 없을 수도 있지만 데모 목적으로 성능을 TreeWalker. 결과를 보려면 jsfiddle에서 직접 테스트를 실행하십시오 .

  1. TreeWalker 사용
  2. 사용자 지정 반복 순회
  3. 사용자 지정 재귀 순회
  4. Xpath 쿼리
  5. querySelectorAll
  6. getElementsByTagName

Text기본적으로 모든 노드 를 가져올 수있는 방법이 있다고 가정 해 보겠습니다 . node.nodeValueDOM 노드와 마찬가지로 실제 텍스트를 얻기 위해 각 결과 텍스트 노드를 탐색하고 호출 해야합니다. 따라서 성능 문제는 텍스트 노드를 반복하는 것이 아니라 텍스트가 아닌 모든 노드를 반복하고 유형을 확인하는 것입니다. 나는 (결과에 근거하여) 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


1
다른 브라우저에서 위의 각 방법에 대해 혼합 된 결과를 얻었습니다. 위의 결과는 Chrome 용입니다. Firefox와 Safari는 매우 다르게 작동합니다. 불행히도 IE에 대한 액세스 권한이 없지만 IE에서 직접 테스트하여 작동하는지 확인할 수 있습니다. 브라우저 최적화에 관해서는 차이가 수십 밀리 초 또는 수백 밀리 초 정도라면 각 브라우저에 대해 다른 방법을 선택하는 것에 대해 걱정할 필요가 없습니다.
Anurag

1
이것은 정말 유용한 대답이지만 다른 방법이 매우 다른 것을 반환한다는 점에 유의하십시오. 그들 중 다수는 부모의 첫 번째 자식 인 경우에만 텍스트 노드를 얻습니다. 그들 중 일부는 텍스트 만 가져올 수있는 반면 다른 일부는 약간의 수정으로 실제 텍스트 노드를 반환 할 수 있습니다. 성능에 영향을 줄 수있는 반복적 트리 탐색에 오류가 있습니다. 변경 node.nodeType = 3node.nodeType == 3
theazureshadow

@theazureshadow-눈부신 =버그 를 지적 해 주셔서 감사합니다 . 나는 그것을 고쳤고, xpath 버전은 Text다른 메소드처럼 실제 문자열이 아니라 단순히 객체 를 반환 했습니다. 첫 번째 아이의 텍스트 만받는 방법은 의도적으로 잘못되었으며 처음에 언급했습니다. 테스트를 다시 실행하고 여기에 업데이트 된 결과를 게시하겠습니다. 모든 테스트 (getElementsByTagName 및 xpath 제외)는 동일한 수의 텍스트 노드를 반환합니다. XPath는 지금은 무시할 다른 노드보다 약 20 개 더 많은 노드를보고합니다.
아 누락

6
나는 테스트를 동등하게 만들고 jsPerf를 만들었다 : jsperf.com/text-node-traversal
Tim Down

1
@TimDown 잘 했어-장애인 테스트는 오랫동안 눈이 아팠다. :) 답으로 추가해야한다 ..
Anurag

5

Iterator가장 빠른 TreeWalker 메서드 의 최신 버전은 다음과 같습니다 .

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 및 Chrome)에서는 스크립트 또는 스타일 태그 콘텐츠를 제외하는 반면 textContent(Firefox 및 Chrome에서는) 포함 하는 것으로 보입니다 .


1
고마워요-내가 원했던 건 아니에요. 내 요구는 DOM이 (부모 등을 찾는 등) 객체로 장소를 검사 할 수있는 요구
levik

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;
  }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.