Domanda

A seguito di una chiamata ajax jQuery per recuperare un intero documento XHTML, qual è il modo migliore per selezionare elementi specifici dalla stringa risultante? Forse c'è una libreria o plugin che risolve questo problema?

jQuery può selezionare gli elementi XHTML che esistono in una stringa solo se sono normalmente ammessi in un div nella specifica W3C; pertanto, sono curioso di selezionare elementi come <title>, <script> e <style>.

Secondo la documentazione di jQuery:

  

http://docs.jquery.com/Core/jQuery#htmlownerDocument

     

La stringa HTML non può contenere   elementi non validi all'interno di a   div, come html, head, body o   elementi del titolo.

Pertanto, poiché abbiamo stabilito che jQuery non fornisce un modo per farlo, come selezionerei questi elementi? Ad esempio, se puoi mostrarmi come selezionare il titolo della pagina remota, sarebbe perfetto!

Grazie, Pete

È stato utile?

Soluzione

Invece di hackerare jQuery per fare questo, ti suggerisco di abbandonare jQuery per un minuto e utilizzare metodi dom XML non elaborati. Usando i metodi XML Dom puoi farlo:

  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);
          }
    });
  }

Non si scherza con iframe ecc.

Altri suggerimenti

Solo un'idea, testata in FF / Safari, sembra funzionare se si crea un iframe per archiviare temporaneamente il documento. Ovviamente, se lo stai facendo, potrebbe essere più intelligente usare semplicemente la proprietà src dell'iframe per caricare il documento e fare quello che vuoi nella & Quot; onload & Quot; di esso.

  $(function() {
    $.ajax({
      type: 'GET', 
      url: 'result.html',
      dataType: 'html',
      success: function(data) {
        var $frame = $("<iframe src='about:blank'/>").hide();
        $frame.appendTo('body');
        var doc = $frame.get(0).contentWindow.document;
        doc.write(data);
        var $title = $("title", doc);
        alert('Title: '+$title.text() );
        $frame.remove();
      }
    });
  });

Ho dovuto aggiungere l'iframe al corpo per farlo avere una finestra .content.

Ispirato da risposta , ma con differito:

function fetchDoc(url) {
  var dfd;
  dfd = $.Deferred();

  $.get(url).done(function (data, textStatus, jqXHR) {

    var $iframe = $('<iframe style="display:none;"/>').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();
};

E fumalo con:

fetchDoc('/foo.html').done(function (data, textStatus, jqXHR) {
  alert($('title', this).text());
});

DEMO LIVE (fai clic su" Esegui ")

Che ne dici di un cambio di nome rapido?

$.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());
    }

});

Funziona. Ho appena diviso i mattoni per una migliore leggibilità.

Controlla la spiegazione e i commenti incorporati per capire il funzionamento di questo e perché deve essere fatto in questo modo.

Ovviamente questo non può essere usato per recuperare contenuti tra domini perché devi proxy le chiamate tramite uno script o pensare all'integrazione come flXHR (Ajax interdominio con Flash)

call.html

<!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</title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="xmlDoc.js" type="text/javascript"></script>
    <script src="output.js" type="text/javascript"></script>
    <script src="ready.js" type="text/javascript"></script>
  </head>
  <body>
    <div>
      <input type="button" id="getit" value="GetIt" />
    </div>
  </body>
</html>

jquery.js è (jQuery 1.3.2 non compresso) test.html un documento XHTML valido

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);
        }
      }
    });
  });
});

In Opera il tutto funziona senza la funzione createXMLDocument e beforeSend.

Il trucco aggiuntivo è necessario per Firefox (3.0.11) e IE6 (impossibile testare IE7, IE8, altri browser) poiché hanno un problema quando Content-Type: restituito dal server non indica che è xml . Il mio server web ha restituito Content-Type: text/html; charset=UTF-8 per test.html. In quei due browser jQuery ha chiamato il error callback con textStatus dicendo parsererror. Perché nella riga 3706 in jQuery.js

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

data è impostato su null. Come in FF e IE xhr.responseXML è nullo. Ciò accade perché non ottengono che i dati restituiti siano xml (come fa Opera). E solo xhr.responseText è impostato con l'intero codice xhtml. Poiché i dati sono nulli, la riga 3708

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

genera un'eccezione rilevata nella riga 3584 e lo stato è impostato su overrideMimeType().

In FF posso risolvere il problema utilizzando la funzione <=> prima di inviare la richiesta.

Ma IE non supporta quella funzione sull'oggetto XMLHttpRequest, quindi devo generare XMLDocument da solo se viene eseguito il callback dell'errore e l'errore è <=>.

esempio per test.html

<?xml version="1.0" encoding="UTF-8" ?>
<!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>Plugins | jQuery Plugins</title>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript">var imagePath = '/content/img/so/';</script>
  </head>
  <body>
  </body>
</html>

Spudoratamente copiato e adattato da un'altra delle mie risposte ( Semplice esempio di jQuery ajax che non trova elementi nell'HTML restituito ), questo recupera l'HTML della pagina remota, quindi la funzione parseHTML crea un elemento div temporaneo per esso e inserisce il lotto all'interno, lo scorre e restituisce l'elemento richiesto. jQuery quindi avvisa il testo () all'interno.

$(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;
}

Per ottenere diversi elementi o un elenco di tag di script, diciamo, penso che dovresti migliorare la funzione parseHTML, ma hey - proof of concept :-)

Se volessi trovare il valore di campi specificatamente denominati (ovvero gli input in un modulo) qualcosa del genere li troverebbe per te:

var fields = ["firstname","surname", ...."foo"];

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

Che ne dici di questo: Carica XML dalla stringa

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

Puoi anche semplicemente avvolgere temporaneamente un div. Non è nemmeno necessario aggiungerlo al DOM.

Dopo aver analizzato la stringa XML in un XML DOM , utilizzerei direttamente jQuery (puoi farlo fornendo un contesto al selettore jQUery , come $ (': title', xdoc.rootElement) o usando XPath (funziona in Firefox; ci sono presumibilmente librerie per IE ma io non hanno avuto un buon successo con loro).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top