2010-04-05 26 views
65

Có cách nào để thu thập tất cả các đối tượng textNode trong tài liệu không?getElementsByTagName() tương đương với các mã văn bản

getElementsByTagName() hoạt động tốt cho Elements, nhưng textNode s không phải là Phần tử.

Cập nhật: Tôi nhận thấy điều này có thể được thực hiện bằng cách đi bộ DOM - như được đề xuất dưới đây. Tôi biết cách viết một hàm DOM-walker nhìn vào mọi nút trong tài liệu. Tôi đã hy vọng có một số cách trình duyệt bản địa để làm điều đó. Sau khi tất cả đó là một chút lạ mà tôi có thể nhận được tất cả các <input> s với một cuộc gọi được xây dựng trong, nhưng không phải tất cả textNode s.

Trả lời

97

Cập nhật:

tôi đã vạch ra một số xét nghiệm hiệu suất cơ bản đối với mỗi một trong các phương pháp 6 trên 1000 chạy. getElementsByTagName là nhanh nhất nhưng nó thực hiện một nửa công việc, vì nó không chọn tất cả các yếu tố, nhưng chỉ có một loại thẻ cụ thể (tôi nghĩ p) và mù quáng giả định rằng firstChild của nó là một phần tử văn bản. Nó có thể hơi thiếu sót nhưng ở đó cho mục đích trình diễn và so sánh hiệu suất của nó với TreeWalker. Run the tests yourselves on jsfiddle để xem kết quả.

  1. Sử dụng một TreeWalker
  2. Tuỳ chỉnh lặp Traversal
  3. Tuỳ chỉnh Recursive Traversal
  4. XPath truy vấn
  5. querySelectorAll
  6. getElementsByTagName

Giả sử trong chốc lát rằng có một phương pháp cho phép bạn nhận tất cả Text nút nguyên bản. Bạn vẫn sẽ phải đi qua từng nút văn bản kết quả và gọi node.nodeValue để nhận được văn bản thực tế giống như bạn thực hiện với bất kỳ Nút DOM nào. Vì vậy, vấn đề hiệu suất không phải là với việc lặp qua các nút văn bản, nhưng lặp qua tất cả các nút không phải là văn bản và kiểm tra loại của chúng. Tôi sẽ tranh luận (dựa trên kết quả) rằng TreeWalker hoạt động nhanh như getElementsByTagName, nếu không nhanh hơn (ngay cả với getElementsByTagName đang chơi khuyết tật).

 
Ran each test 1000 times. 

Method     Total ms  Average ms 
-------------------------------------------------- 
document.TreeWalker   301   0.301 
Iterative Traverser   769   0.769 
Recursive Traverser   7352   7.352 
XPath query     1849   1.849 
querySelectorAll   1725   1.725 
getElementsByTagName   212   0.212 

Nguồn cho từng phương pháp:

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

Recursive Tree Traversal

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

lặp Tree Traversal

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

Ngoài ra, bạn có thể tìm thấy thảo luận này có hữu ích - http://bytes.com/topic/javascript/answers/153239-how-do-i-get-elements-text-node

+0

Thú vị .. Có 'createTreeWalker()' làm việc trên IE không? – levik

+0

Tôi đã nhận được kết quả hỗn hợp cho từng phương pháp ở trên trong trình duyệt khác nhau - những kết quả này ở trên dành cho Chrome. Firefox và Safari hoạt động rất khác nhau. Tôi không có quyền truy cập vào IE không may, nhưng bạn có thể kiểm tra các bản thân trên IE để xem nó có hoạt động hay không. Đối với tối ưu hóa trình duyệt, tôi sẽ không lo lắng về việc chọn một phương pháp khác nhau cho mỗi trình duyệt miễn là sự khác biệt là theo thứ tự của hàng chục mili giây hoặc thậm chí là hàng trăm thấp. – Anurag

+1

Đây là một câu trả lời thực sự hữu ích, nhưng hãy cẩn thận rằng các phương pháp khác nhau trả về những điều rất khác nhau. Nhiều người trong số họ chỉ nhận được các nút văn bản nếu họ là con đầu tiên của cha mẹ của họ. Một số người trong số họ chỉ có thể nhận được văn bản, trong khi những người khác có thể trả lại các nút văn bản thực tế với những sửa đổi nhỏ. Có lỗi trong Chuyển đổi cây lặp đi lặp lại có thể ảnh hưởng đến hiệu suất của nó. Thay đổi 'node.nodeType = 3' thành' node.nodeType == 3' – theazureshadow

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

/* Bạn có thể trả về một mảng của tất cả các nút văn bản hậu duệ của một số yếu tố phụ huynh, hoặc bạn có thể vượt qua nó một số chức năng và làm một cái gì đó (tìm hoặc thay thế hoặc bất cứ điều gì) cho văn bản tại chỗ.

Ví dụ này trả về nội dung của textnodes phi khoảng trắng trong cơ thể:

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

*/

Handy cho tìm kiếm và thay thế, làm nổi bật và vân vân

4

Tôi biết bạn đặc biệt yêu cầu một bộ sưu tập, nhưng nếu bạn chỉ có nghĩa là không chính thức và không quan tâm nếu tất cả chúng được nối với nhau thành một chuỗi lớn, bạn có thể sử dụng:

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

... với mục đầu tiên là cách tiếp cận tiêu chuẩn DOM3. Tuy nhiên, lưu ý rằng innerText dường như loại trừ nội dung thẻ tập lệnh hoặc kiểu trong các triển khai hỗ trợ (ít nhất là IE và Chrome) trong khi textContent bao gồm chúng (trong Firefox và Chrome).

+1

Cảm ơn - đó không phải là những gì tôi muốn mặc dù. Nhu cầu của tôi gọi để có thể kiểm tra chúng tại chỗ như đối tượng DOM (như tìm cha mẹ, v.v.) – levik

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

Dưới đây là một phiên bản hiện đại Iterator của phương pháp TreeWalker nhanh nhất:

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

Cách sử dụng:

const textNodes = [...getTextNodesIterator(document.body)]; 

Hoặc thú vị hơn, với một vòng lặp for-of:

for (const textNode of getTextNodesIterator(document.body)) { 
    console.log(textNode) 
} 
Các vấn đề liên quan