2010-03-28 18 views
6

Mi proyecto actual consiste en reunir contenido de texto de un elemento y todos sus descendientes, en función de un selector provisto.JavaScript: ¿Cómo obtener texto de todos los descendientes de un elemento sin tener en cuenta los scripts?

Por ejemplo, cuando se suministra el selector #content y ejecutarse sobre este HTML:

<div id="content"> 
    <p>This is some text.</p> 
    <script type="text/javascript"> 
    var test = true; 
    </script> 
    <p>This is some more text.</p> 
</div> 

mi guión volvería (después de un poco de limpieza de espacios en blanco):

Esto es un texto. var test = verdadero; Este es un poco más de texto.

Sin embargo, necesito ignorar los nodos de texto que se producen dentro de los elementos <script>.

Este es un extracto de mi código actual (técnicamente, de que coincida basa en uno o selectores más proporcionadas):

// get text content of all matching elements 
for (x = 0; x < selectors.length; x++) { // 'selectors' is an array of CSS selectors from which to gather text content 
    matches = Sizzle(selectors[x], document); 
    for (y = 0; y < matches.length; y++) { 
    match = matches[y]; 
    if (match.innerText) { // IE 
     content += match.innerText + ' '; 
    } else if (match.textContent) { // other browsers 
     content += match.textContent + ' '; 
    } 
    } 
} 

Es un poco demasiado simplista, ya que sólo devuelve todos los nodos de texto dentro del elemento (y sus descendientes) que coincide con el selector provisto. La solución que estoy buscando devolvería todos los nodos de texto, excepto aquellos que están dentro de los elementos <script>. No es necesario que sea especialmente de alto rendimiento, pero sí necesito que sea finalmente compatible con varios navegadores.

Supongo que tendré que recorrer de algún modo todos los elementos secundarios del elemento que coincida con el selector y acumular todos los nodos de texto distintos de los que están dentro de los elementos <script>; no parece que haya ninguna forma de identificar JavaScript una vez que ya se ha incorporado a la cadena acumulada de todos los nodos de texto.

No puedo usar jQuery (por motivos de rendimiento/ancho de banda), aunque es posible que hayas notado que utilizo su motor de selector Sizzle, por lo que la lógica de selector de jQuery está disponible.

¡Gracias de antemano por cualquier ayuda!

Respuesta

8
function getTextContentExceptScript(element) { 
    var text= []; 
    for (var i= 0, n= element.childNodes.length; i<n; i++) { 
     var child= element.childNodes[i]; 
     if (child.nodeType===1 && child.tagName.toLowerCase()!=='script') 
      text.push(getTextContentExceptScript(child)); 
     else if (child.nodeType===3) 
      text.push(child.data); 
    } 
    return text.join(''); 
} 

O, si se le permite cambiar el DOM para eliminar los elementos <script> (que no suele tener efectos secundarios notables), más rápido:

var scripts= element.getElementsByTagName('script'); 
while (scripts.length!==0) 
    scripts[0].parentNode.removeChild(scripts[0]); 
return 'textContent' in element? element.textContent : element.innerText; 
+0

¡Impresionante, gracias, bobince! Fui con el primer enfoque, probablemente tengas razón en que eliminar los elementos '

2

EDITAR:

Bueno, primero déjeme decir que no estoy demasiado familiarizado con chisporroteo en su solitaria, jsut dentro de las bibliotecas que lo utilizan ... Dicho esto ..

Si tuviera que hacer esto Haría algo como:

var selectors = new Array('#main-content', '#side-bar'); 
function findText(selectors) { 
    var rText = ''; 
    sNodes = typeof selectors = 'array' ? $(selectors.join(',')) : $(selectors); 
    for(var i = 0; i < sNodes.length; i++) { 
     var nodes = $(':not(script)', sNodes[i]); 
     for(var j=0; j < nodes.length; j++) { 
     if(nodes[j].nodeType != 1 && node[j].childNodes.length) { 
      /* recursion - this would work in jQ not sure if 
       * Sizzle takes a node as a selector you may need 
       * to tweak. 
       */ 
      rText += findText(node[j]); 
     } 
     } 
    } 

    return rText; 
} 

No he probado nada de eso, pero debería darle una idea. Con suerte tubería alguien más lo hará con más sentido :-)


Cant que acaba de agarrar el nodo padre y comprueba la nodeName en su bucle ... como:

if(match.parentNode.nodeName.toLowerCase() != 'script' && match.nodeName.toLowerCase() != 'script') { 
    match = matches[y]; 
    if (match.innerText) { // IE 
     content += match.innerText + ' '; 
    } else if (match.textContent) { // other browsers 
     content += match.textContent + ' '; 
    } 
} 

supuesto jQuery soporta el not() sintaxis en los selectores, ¿podría simplemente hacer $(':not(script)')?

+0

Gracias prodigitalson - no estoy seguro Sin embargo, esto lograría mi objetivo. Podría haber sido un poco vago en mi ejemplo de código (simplemente lo he editado): lo que hace es atravesar una matriz de selectores CSS, y para cada uno que coincide con un nodo DOM, simplemente obtiene el texto interno (IE) o contenido de texto (otro) propiedad de ese nodo. En realidad, no recorre los elementos de los niños. Sin embargo, creo que este último es probablemente la mejor manera de hacerlo: recorrer todos los descendientes del elemento coincidente, sin tener en cuenta los nodos de texto en