javascript - ejemplo - getelementsbytagname vba
getElementsByTagName() equivalente para textNodes (5)
¿Hay alguna forma de obtener la colección de todos los objetos textNode
dentro de un documento?
getElementsByTagName()
funciona muy bien para Elements, pero textNode
s no son Elements.
Actualización: me doy cuenta de que esto se puede lograr caminando el DOM, como sugieren muchos de los siguientes. Sé cómo escribir una función DOM-walker que examina todos los nodos del documento. Esperaba que hubiera alguna forma nativa de navegador para hacerlo. Después de todo, es un poco extraño que pueda obtener todas las <input>
s con una sola llamada incorporada, pero no con todas las textNode
.
Aquí hay una versión moderna del Iterator
del método TreeWalker más rápido:
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;
}
Uso:
const textNodes = [...getTextNodesIterator(document.body)];
O más interesante, con un ciclo for-of
:
for (const textNode of getTextNodesIterator(document.body)) {
console.log(textNode)
}
Sé que específicamente solicitó una colección, pero si solo quiso decir informalmente y no le importó si estuvieran todos unidos en una sola cadena grande, puede usar:
var allTextAsString = document.documentElement.textContent || document.documentElement.innerText;
... siendo el primer elemento el enfoque estándar DOM3. Sin embargo, innerText
cuenta que innerText
parece excluir los contenidos de las secuencias de comandos o estilos en las implementaciones que lo soportan (al menos IE y Chrome), mientras que textContent
incluye (en Firefox y Chrome).
Actualización :
He descrito algunas pruebas de rendimiento básicas para cada uno de estos 6 métodos en más de 1000 carreras. getElementsByTagName
es el más rápido, pero tiene un trabajo a medias, ya que no selecciona todos los elementos, sino solo un tipo particular de etiqueta (creo que p
) y supone ciegamente que su firstChild es un elemento de texto. Puede ser poco defectuoso, pero está ahí para fines de demostración y para comparar su rendimiento con TreeWalker
. Ejecute las pruebas en jsfiddle para ver los resultados.
- Usando un TreeWalker
- Trayectoria Iterativa Personalizada
- Trayectoria recursiva personalizada
- Consulta de Xpath
- querySelectorAll
- getElementsByTagName
Supongamos por un momento que hay un método que le permite obtener todos los nodos de Text
forma nativa. Todavía tendría que atravesar cada nodo de texto resultante y llamar a node.nodeValue
para obtener el texto real como lo haría con cualquier nodo DOM. Entonces, el problema del rendimiento no es iterar a través de nodos de texto, sino iterar a través de todos los nodos que no son texto y verificar su tipo. Yo argumentaría (basado en los resultados) que TreeWalker
funciona tan rápido como getElementsByTagName
, si no más rápido (incluso con getElementsByTagName jugando con handicapped).
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
Fuente para cada método:
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);
}
Iterative 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 */
}
}
Además, es posible que encuentre útil este debate: http://bytes.com/topic/javascript/answers/153239-how-do-i-get-elements-text-node
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;
}
/ * Puede devolver una matriz de todos los nodos de texto descendientes de algún elemento principal, o puede pasarle alguna función y hacer algo (buscar o reemplazar o lo que sea) al texto en su lugar.
Este ejemplo devuelve el texto de los nodos de texto que no son de espacio en blanco en el cuerpo:
var A= document.deepText(document.body, function(t){
var tem= t.data;
return //S/.test(tem)? tem: undefined;
});
alert(A.join(''/n''))
* /
Útil para buscar y reemplazar, resaltar, etc.
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)