Actualmente estoy tratando de obtener el contenido del cuerpo de un iframe sin que el navegador manipule el contenido.

Podría hacerlo incluyendo el contenido en un área de texto, sin embargo, quiero evitarlo.

El uso de .innerHTML da como resultado que caracteres especiales como < > y & se conviertan en &lt;, &gt; y &amp; respectivamente.

Para probar, cree un archivo html que contenga:

{ 
 "id": 5, 
 "testtext":"I am > than this & < that", 
 "html":"<div>\"worky\"</div>" 
}

Y luego otra página que incluye ese archivo en un iframe:

<!doctype html>
<html>
  <head>
    <script src="http://code.jquery.com/jquery-latest.js"></script>
  </head>
  <body>
    <iframe id="myIframe" name="myIframe" src="test.html"></iframe><br />
    Result:<br />
    <textarea id='result'></textarea>
    <script>
      $("#myIframe").load(function(){
        var iframeBody = window.frames.myIframe.document
            .getElementsByTagName("body")[0], result;
        result = iframeBody.innerHTML;
        $("#result").val(result);
      });
    </script>
  </body>
</html>

He probado esto:

result = $(iframeBody).contents().map(function(){
      return this.nodeValue ? this.nodeValue : this.innerHTML;
}).get().join("");

Sin embargo, pierde el div.

EDITAR:

Tengo algo de una solución,

var iframeBody, result;
$("#myIframe").load(function(){
  iframeBody = window.frames.myIframe.document
    .getElementsByTagName("body")[0];
  result = $(iframeBody).contents().map(function(){
    if (this.nodeValue) {
        return this.nodeValue   
    }
    else {
        return $(this).clone().wrap('<p>').parent().html();
    }
  }).get().join("");
  $("#result").val(result);
});

Sin embargo, todavía codificará cosas dentro del html que no son html. No estoy seguro si estoy de acuerdo con eso.

EDITAR DE NUEVO

Aquí hay un poco más de contexto. Estoy modificando un transporte jquery iframe ajax para que funcione sin requerir un área de texto en el iframe para contener el contenido cuando el contenido no es html. En su mayor parte, funciona bien sin un área de texto, sin embargo, termina manipulando caracteres html especiales cuando recupera ese texto usando .innerHTML. Una forma de evitar la manipulación es obtener el texto usando .nodeValue, sin embargo, eso no funciona cuando te encuentras con un elemento html. Si devuelve json que contiene una cadena html por cualquier motivo, debe poder extraer esa cadena json exactamente como se devolvió dentro del iframe, lo que significa dejar todos los caracteres intactos.

Para fines de prueba, este jsfiddle es suficiente prueba. Imagine que el div utilizado en el violín es el cuerpo del iframe y puede probar los resultados en jsfiddle. El problema que tengo realmente no tiene nada que ver con el iframe o su evento de carga.

http://jsfiddle.net/P623a/2/

En ese violín, el único problema es que & se convierte a & dentro del div dentro del json.

Solución

Solo voy a requerir que la página esté codificada correctamente (aplicación / json, script o texto plano) si la respuesta es json / jsonp / script y contiene un elemento dom. Si no se codifica correctamente en esas condiciones, se activa el controlador de errores.

Cuando se codifica correctamente, el iframe terminará teniendo una etiqueta de cuerpo que contiene <pre>your content</pre> que puede obtener el contenido de usar .innerText mientras conserva los caracteres especiales.

-1
Kevin B 1 sep. 2011 a las 01:42

4 respuestas

Creo que primero debe probar con un html válido si planea usar nodeValue o, de lo contrario, no puede simplemente asumir que el navegador agregará el cuerpo por usted, esto no es html en absoluto:

{ 
 "id": 5, 
 "testtext":"I am > than this & < that", 
 "html":"<div>\"worky\"</div>" 
}

¡Es extraño intentar analizar un dom que no es html! El hecho es que si desea tener alguna oportunidad de manipular o atravesar jQuery, debe al menos envolver todas las cosas en un gran contenedor como:

<div>
// even if you don't want use body or html tag, things must be wrapped here
</div>

Creo que hay un problema de una idea errónea de qué y cómo estás tratando de satisfacer tus necesidades, ¿no debería ser más fácil cargar algo de json (como escribiste)? estás tratando de rodar un cubo ... si no quieres analizar tus datos puros a través de dom de todos modos, puedes probar algo como esto:

<p>
<p>id<span>5</span></p>
<p>testtext<span>I "am" > than this & < that</span></p>
</p>

Por supuesto, simplemente no puede insertar html como texto sin formato porque ¿cómo se supone que el navegador sabe qué hacer? Solo haz una prueba simple:

var div = $('<div/>').appendTo('body').html('I "am" > than this & < that');
console.log('plainText :', div.text(), ', html :', div.html());
// works as expected...
1
dmidz 6 sep. 2011 a las 10:58

¿Puedes url codificar tu cadena JSON antes de pasarla al iframe? Por ejemplo ... si cambia su cadena html: "<div>\"worky\"</div>" a "&lt;div>\"worky\"&lt;/div>", muestra el div html correctamente. Los elementos div se escriben en el dom cuando se carga el iframe, por lo que debe evitar que analice correctamente los elementos html en su cadena.

0
Kevin M 4 sep. 2011 a las 17:23

El código que tiene en test1.html no tiene "cuerpo", no puede .getElementsByTagName("body") si no hay cuerpo. Tratar:

$("#myIframe").load(function(){
    $("#result").val($(this).contents().text());
});
1
Rusty Jeans 31 ago. 2011 a las 22:26

Está configurando el controlador de eventos de carga iframe después de la etiqueta iframe que ya tiene la fuente. Por lo tanto, es posible que el iframe se cargue antes de que se adjunte el controlador de eventos load. No digo que este sea el problema, pero esto creará un problema si el iframe se carga rápidamente. Puede proporcionar un controlador de eventos de carga en línea en la propia etiqueta iframe.

Prueba esto

<!doctype html>
<html>
  <head>
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script type="text/javascript">
    function copyIframeContent(iframe){
        var iframeContent = $(iframe).contents();
        $("#result").html(iframeContent.find('body').html());
    }
    </script>
  </head>
  <body>
    <iframe id="myIframe" onload="copyIframeContent(this);" name="myIframe" src="test.html"></iframe><br />
    Result:<br />
    <textarea id='result'></textarea>
  </body>
</html>

Espero que esto te ayude.

1
ShankarSangoli 4 sep. 2011 a las 01:51