¿Cuál es la mejor práctica para analizar el contenido remoto con jQuery?

Después de una llamada jQuery ajax para recuperar un documento XHTML completo, ¿cuál es la mejor manera de seleccionar elementos específicos de la cadena resultante? Tal vez hay una biblioteca o un complemento que resuelve este problema?

jQuery solo puede seleccionar elementos XHTML que existen en una cadena si normalmente están permitidos en un div en la especificación W3C; por lo tanto, tengo curiosidad por seleccionar cosas como </code> , <code></code> y <code></code> . </p> <p> De acuerdo con la documentación jQuery: </p><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <ins class="adsbygoogle" style="display:block; text-align:center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-4943387893641281" data-ad-slot="3975015553"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> <blockquote> <p> http://docs.<a href="https://www.dokry.com/do/jquery" title="Topics of jquery" target="_blank">jquery</a>.com/Core/jQuery#htmlownerDocument </p><ul><li><a class="text-dark" href="https://www.dokry.com/11502" rel="bookmark" title="Número de fila y columna de la tabla en jQuery">Número de fila y columna de la tabla en jQuery</a></li><li><a class="text-dark" href="https://www.dokry.com/27884" rel="bookmark" title="Use Jquery Selectors en $ .AJAX cargado HTML?">Use Jquery Selectors en $ .AJAX cargado HTML?</a></li><li><a class="text-dark" href="https://www.dokry.com/12500" rel="bookmark" title="puede jqgrid support desplegables en los campos de filtro de la barra de herramientas">puede jqgrid support desplegables en los campos de filtro de la barra de herramientas</a></li><li><a class="text-dark" href="https://www.dokry.com/13744" rel="bookmark" title="¿Cómo cambiar las opciones de con jQuery?">¿Cómo cambiar las opciones de con jQuery?</a></li><li><a class="text-dark" href="https://www.dokry.com/35163" rel="bookmark" title="La función de Javascript no puede devolver el elemento">La función de Javascript no puede devolver el elemento</a></li></ul> <p> La cadena HTML no puede contener elementos que no son válidos dentro de un div, como elementos html, head, body o title. </p> </blockquote> <p> Por lo tanto, como hemos establecido que jQuery no proporciona una forma de hacerlo, ¿cómo seleccionaría estos elementos? Como ejemplo, si puede mostrarme cómo seleccionar el título de la página remota, ¡sería perfecto! </p> <p> Gracias, Pete </p> <div class='row'> <div class='col'> <ul><li><a class="text-dark" href="https://www.dokry.com/23179" rel="bookmark" title="jQuery dot en el selector de ID?">jQuery dot en el selector de ID?</a></li><li><a class="text-dark" href="https://www.dokry.com/48394" rel="bookmark" title="¿Cómo usar Twitter Bootstrap popovers para jQuery notificaciones de validación?">¿Cómo usar Twitter Bootstrap popovers para jQuery notificaciones de validación?</a></li><li><a class="text-dark" href="https://www.dokry.com/3237" rel="bookmark" title="jQuery diferido y promesas - .then () vs .done ()">jQuery diferido y promesas - .then () vs .done ()</a></li><li><a class="text-dark" href="https://www.dokry.com/49585" rel="bookmark" title="Datatable date sorting dd / mm / yyyy issue">Datatable date sorting dd / mm / yyyy issue</a></li><li><a class="text-dark" href="https://www.dokry.com/39218" rel="bookmark" title="jQuery: hacer que las casillas de verificación actúen como botones de radio?">jQuery: hacer que las casillas de verificación actúen como botones de radio?</a></li><li><a class="text-dark" href="https://www.dokry.com/52818" rel="bookmark" title="Cómo cambiar solo el nodo de texto en el elemento">Cómo cambiar solo el nodo de texto en el elemento</a></li></ul> </div> </div> <div class="list-group list-group-flush"> <div class="list-group-item list-group-item-action flex-column align-items-start"> <p> En lugar de hackear jQuery para hacer esto, le sugiero que abandone jQuery por un minuto y use métodos raw XML dom. Usando métodos XML Dom, puedes hacer esto: </p> <pre> <code> window.onload = function(){ $.ajax({ type: 'GET', url: 'text.html', dataType: 'html', success: function(data) { //cross platform xml object creation from w3schools try //Internet Explorer { xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async="false"; xmlDoc.loadXML(data); } catch(e) { try // Firefox, Mozilla, Opera, etc. { parser=new DOMParser(); xmlDoc=parser.parseFromString(data,"text/xml"); } catch(e) { alert(e.message); return; } } alert(xmlDoc.getElementsByTagName("title")[0].childNodes[0].nodeValue); } }); }</code> </pre> <p> Sin jugar con iframes, etc. </p> </div> </li><!-- #comment-## --> <div class="list-group-item list-group-item-action flex-column align-items-start"> <p> Solo una idea, probada en FF / Safari, parece funcionar si crea un iframe para almacenar el documento temporalmente. Por supuesto, si está haciendo esto, podría ser más inteligente simplemente usar la propiedad src del iframe para cargar el documento y hacer lo que quiera en la “carga” del mismo. </p> <pre> <code> $(function() { $.ajax({ type: 'GET', url: 'result.html', dataType: 'html', success: function(data) { var $frame = $("<iframe src='about:blank'></iframe>").hide(); $frame.appendTo('body'); var doc = $frame.get(0).contentWindow.document; doc.write(data); var $title = $("title", doc); alert('Title: '+$title.text() ); $frame.remove(); } }); });</code> </pre> <p> Tuve que agregar el iframe al cuerpo para que tuviera una .contentWindow. </p> </div> </li><!-- #comment-## --> <div class="list-group-item list-group-item-action flex-column align-items-start"> <p> Inspirado de esta respuesta , pero con diferido: </p> <pre> <code>function fetchDoc(url) { var dfd; dfd = $.Deferred(); $.get(url).done(function (data, textStatus, jqXHR) { var $iframe = $('<iframe style="display:none;"></iframe>').appendTo('body'); var $doc = $iframe.contents(); var doc = $doc[0]; $iframe.load(function() { dfd.resolveWith(doc, [data, textStatus, jqXHR]); return $iframe.remove(); }); doc.open(); doc.write(data); return doc.close(); }).fail(dfd.reject); return dfd.promise(); };</code> </pre> <p> Y fumarlo con: </p> <pre> <code>fetchDoc('/foo.html').done(function (data, textStatus, jqXHR) { alert($('title', this).text()); });</code> </pre> <p> DEMO EN VIVO (haga clic en ‘Ejecutar’) </p> </div> </li><!-- #comment-## --> <div class="list-group-item list-group-item-action flex-column align-items-start"> <p> ¿Qué tal un cambio de nombre rápido de etiqueta? </p> <pre> <code>$.ajax({ type : "GET", url : 'results.html', dataType : "html", success: function(data) { data = data.replace(/html/g, "xhtmlx"); data = data.replace(/head/g, "xheadx"); data = data.replace(/title/g, "xtitlex"); data = data.replace(/body/g, "xbodyx"); alert($(data).find("xtitlex").text()); } });</code> </pre> </div> </li><!-- #comment-## --> <div class="list-group-item list-group-item-action flex-column align-items-start"> <p> Esto funciona. Acabo de dividir los bloques de construcción para una mejor legibilidad. </p> <p> Verifique la explicación y los comentarios en línea para comprender el funcionamiento de esto y por qué tiene que hacerse así. </p> <p> Por supuesto, esto no se puede utilizar para recuperar contenido de dominio cruzado para el que tenga que usar las secuencias de comandos a través de un script suyo o pensar en la integración de algo así como flXHR (Cross-Domain Ajax con Flash) </p> <p> <strong>call.html</strong> </p> <pre> <code><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <title>asd

jquery.js es (jQuery 1.3.2 descomprimido) test.html un documento XHTML válido

xmlDoc.js

 // helper function to create XMLDocument out of a string jQuery.createXMLDocument = function( s ) { var xmlDoc; // is it a IE? if ( window.ActiveXObject ) { xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); xmlDoc.async = "false"; // prevent erros as IE tries to resolve the URL in the DOCTYPE xmlDoc.resolveExternals = false; xmlDoc.validateOnParse = false; xmlDoc.loadXML(s); } else { // non IE. give me DOMParser // theoretically this else branch should never be called // but just in case. xmlDoc = ( new DOMParser() ).parseFromString( s, "text/xml" ); } return xmlDoc; }; 

output.js

 // Output the title of the loaded page // And get the script-tags and output either the // src attribute or code function headerData(data) { // give me the head element var x = jQuery("head", data).eq(0); // output title alert(jQuery("title", x).eq(0).text()); // for all scripttags which include a file out put src jQuery("script[src]", x).each(function(index) { alert((index+1)+" "+jQuery.attr(this, 'src')); }); // for all scripttags which are inline javascript output code jQuery("script:not([src])", x).each(function(index) { alert(this.text); }); } 

ready.js

 $(document).ready(function() { $('#getit').click(function() { $.ajax({ type : "GET", url : 'test.html', dataType : "xml", // overwrite content-type returned by server to ensure // the response getst treated as xml beforeSend: function(xhr) { // IE doesn't support this so check before using if (xhr.overrideMimeType) { xhr.overrideMimeType('text/xml'); } }, success: function(data) { headerData(data); }, error : function(xhr, textStatus, errorThrown) { // if loading the response as xml failed try it manually // in theory this should only happen for IE // maybe some if (textStatus == 'parsererror') { var xmlDoc = jQuery.createXMLDocument(xhr.responseText); headerData(xmlDoc); } else { alert("Failed: " + textStatus + " " + errorThrown); } } }); }); }); 

En Opera todo funciona sin el createXMLDocument y la función beforeSend .

El truco adicional es necesario para Firefox (3.0.11) e IE6 (no puede probar IE7, IE8, otros navegadores) ya que tienen un problema cuando Content-Type: devuelto por el servidor no indica que sea xml. Mi servidor web devolvió Content-Type: text/html; charset=UTF-8 Content-Type: text/html; charset=UTF-8 para test.html. En esos dos navegadores jQuery llamó a la callback de error con textStatus diciendo parsererror . Porque en la línea 3706 en jQuery.js

 data = xml ? xhr.responseXML : xhr.responseText; 

data se establecen en nulo. Como en FF e IE, xhr.responseXML es nulo. Esto sucede porque no entienden que los datos devueltos son xml (como lo hace Opera). Y solo xhr.responseText se establece con el código xhtml completo. Como los datos son nulos, la línea 3708

 if ( xml && data.documentElement.tagName == "parsererror" ) 

arroja una excepción atrapada en la línea 3584 y el estado se establece en parsererror .

En FF puedo resolver el problema utilizando la función overrideMimeType() antes de enviar la solicitud.

Pero IE no admite esa función en el objeto XMLHttpRequest, así que tengo que generar el XMLDocument yo mismo si se ejecuta el error-callback y el error es parsererror .

ejemplo para test.html

      Plugins | jQuery Plugins       

Sin vergüenza copiado y adaptado de otra de mis respuestas ( Ejemplo simple de jQuery ajax que no encuentra elementos en HTML devuelto ), esto obtiene el HTML de la página remota, luego la función parseHTML crea un elemento div temporal para él y pone el lote adentro, se ejecuta y devuelve el elemento solicitado. jQuery luego alerta el texto () dentro.

 $(document).ready(function(){ $('input').click(function(){ $.ajax({ type : "POST", url : 'ajaxtestload.html', dataType : "html", success: function(data) { alert( data ); // shows whole dom var gotcha = parseHTML(data, 'TITLE'); // nodeName property returns uppercase if (gotcha) { alert($(gotcha).html()); // returns null }else{ alert('Tag not found.'); } }, error : function() { alert("Sorry, The requested property could not be found."); } }); }); }); function parseHTML(html, tagName) { var root = document.createElement("div"); root.innerHTML = html; // Get all child nodes of root div var allChilds = root.childNodes; for (var i = 0; i < allChilds.length; i++) { if (allChilds[i].nodeName == tagName) { return allChilds[i]; } } return false; } 

Para sacar varios elementos o una lista de tags de secuencia de comandos, por ejemplo, creo que tendrías que mejorar la función parseHTML, pero bueno, prueba de concepto 🙂

Si quisieras encontrar el valor de campos específicamente nombrados (es decir, las entradas en un formulario) algo como esto los encontraría por ti:

 var fields = ["firstname","surname", ...."foo"]; function findFields(form, fields) { var form = $(form); fields.forEach(function(field) { var val = form.find("[name="+field+"]").val(); .... 

¿Qué tal esto? Cargar XML de una cadena

 $.get('yourpage.html',function(data){ var content = $('
').append(data).find('#yourelement').html(); });

También puede simplemente envolver temporalmente dentro de un div. Ni siquiera necesita agregarlo al DOM.

Después de analizar la cadena XML en un XML DOM , usaría jQuery en él directamente (puede hacer esto proporcionando un contexto para el selector de jQUery , como $(':title', xdoc.rootElement) o usando XPath ( funciona en Firefox, supuestamente hay bibliotecas para IE pero no he tenido mucho éxito con ellas).