ドキュメント内のすべてのtextNode
オブジェクトのコレクションを取得する方法はありますか?
getElementsByTagName()
はElementsには最適ですが、textNode
sはElementsではありません。
pdate:これは、DOMをウォークすることで実現できることを理解しています。文書内のすべてのノードを調べるDOM-walker関数を作成する方法を知っています。私はそれを行うためのいくつかのブラウザネイティブの方法があることを望んでいました。結局のところ、単一の組み込み呼び出しですべての<input>
sを取得できるが、すべてのtextNode
sを取得できないのは少し奇妙です。
更新:
これらの6つの方法のそれぞれについて、1000回以上の実行でいくつかの基本的なパフォーマンステストを概説しました。 getElementsByTagName
は最速ですが、すべての要素を選択するのではなく、特定の1つのタイプのタグのみ(p
だと思います)であり、firstChildがテキスト要素。少し欠陥があるかもしれませんが、デモ目的であり、そのパフォーマンスをTreeWalker
と比較しています。 jsfiddleで自分でテストを実行 結果を確認します。
しばらくの間、すべての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
コレクションを具体的に要求したことは知っていますが、それを非公式に意味するだけで、すべてが1つの大きな文字列に結合されているかどうかを気にしない場合は、次のように使用できます。
var allTextAsString = document.documentElement.textContent || document.documentElement.innerText;
...最初の項目はDOM3標準アプローチです。ただし、innerText
は、それをサポートする実装(少なくともIEおよびChrome))でスクリプトまたはスタイルタグのコンテンツを除外しているように見えますが、textContent
はそれらを含みます(Firefoxの場合)およびChrome)。
これが最速の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;
}
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'))
* /
検索、置換、ハイライトなどに便利
これはもう少し慣用的で、(うまくいけば)理解しやすい代替案です。
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
}
}
}
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)