Как лучше всего разбирать удаленный контент с помощью jQuery? - PullRequest
35 голосов
/ 24 июня 2009

После вызова jQuery ajax для получения всего документа XHTML, каков наилучший способ выбора определенных элементов из полученной строки? Возможно, есть библиотека или плагин, который решает эту проблему?

jQuery может выбирать элементы XHTML, которые существуют в строке, только если они обычно разрешены в div в спецификации W3C; поэтому мне любопытно выбрать такие вещи, как <title>, <script> и <style>.

Согласно документации jQuery:

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

Строка HTML не может содержать элементы, которые недопустимы в div, такой как html, head, body или элементы заголовка.

Поэтому, поскольку мы установили, что jQuery не предоставляет способ сделать это, как бы я выбрал эти элементы? Например, если вы можете показать мне, как выбрать заголовок удаленной страницы, это было бы идеально!

Спасибо, Пит

Ответы [ 10 ]

29 голосов
/ 01 июля 2009

Вместо того, чтобы взламывать jQuery для этого, я бы посоветовал вам на минуту отказаться от jQuery и использовать сырые методы XML dom. Используя методы XML Dom, вы можете сделать это:

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

Не возиться с фреймами и т. Д.

5 голосов
/ 27 июня 2009

Просто идея, проверенная в FF / Safari, кажется, работает, если вы создаете iframe для временного хранения документа. Конечно, если вы делаете это, может быть разумнее просто использовать свойство src iframe для загрузки документа и делать все, что вы хотите в его «onload».

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

Мне пришлось добавить iframe к телу, чтобы получить .contentWindow.

3 голосов
/ 08 июля 2012

Вдохновленный этот ответ , но с отложенным:

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

И выкури это с:

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

LIVE DEMO (нажмите «Выполнить»)

2 голосов
/ 28 июня 2009

Это работает. Я просто разделил строительные блоки для лучшей читаемости.

Проверьте объяснение и встроенные комментарии, чтобы понять, как это работает, и почему это должно быть сделано так.

Конечно, это не может быть использовано для получения междоменного контента, для этого вам нужно либо прокси-вызовы через ваш скрипт, либо подумать об интеграции чего-то вроде flXHR (междоменный Ajax с 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 is (несжатый jQuery 1.3.2) test.html действительный XHTML-документ

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

В Opera все работает без функции createXMLDocument и beforeSend.

Дополнительная хитрость необходима для Firefox (3.0.11) и IE6 (не удается протестировать IE7, IE8, другие браузеры), так как они имеют проблему, когда Content-Type:, возвращаемый сервером, не указывает, что это xml , Мой веб-сервер возвратил Content-Type: text/html; charset=UTF-8 для test.html. В этих двух браузерах jQuery назвал обратный вызов error с textStatus, говоря parsererror. Потому что в строке 3706 в jQuery.js

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

data устанавливается на ноль. Как и в FF и IE, xhr.responseXML является нулевым. Это происходит потому, что они не получают возвращаемые данные в формате xml (как это делает Opera). И только xhr.responseText задается с целым xhtml-кодом. Поскольку данные нулевые, строка 3708

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

выдает исключение, которое перехватывается в строке 3584, и статус устанавливается на parsererror.

В FF я могу решить проблему с помощью функции overrideMimeType() перед отправкой запроса.

Но IE не поддерживает эту функцию для объекта XMLHttpRequest, поэтому я должен сам сгенерировать XMLDocument, если выполняется обратный вызов с ошибкой и ошибка parsererror.

пример для 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>
2 голосов
/ 26 июня 2009

Как насчет быстрого переименования тегов?

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

});
1 голос
/ 24 июня 2009

Бесстыдно скопировано и адаптировано из другого моего ответа ( Простой пример jQuery ajax не находит элементы в возвращенном HTML ), это выбирает HTML-код удаленной страницы, затем функция parseHTML создает временный элемент div он помещает лот внутрь, проходит через него и возвращает запрошенный элемент. Затем jQuery предупреждает текст () внутри.

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

Чтобы вывести несколько элементов или список тегов скрипта, скажем, я думаю, вам нужно улучшить функцию parseHTML, но эй - подтверждение концепции: -)

0 голосов
/ 17 сентября 2012
$.get('yourpage.html',function(data){
    var content = $('<div/>').append(data).find('#yourelement').html();
});

Вы также можете просто временно обернуть внутри div. Вам даже не нужно добавлять его в DOM.

0 голосов
/ 01 июля 2009

После разбора XML-строки в XML DOM я бы либо использовал jQuery непосредственно для нее (вы можете сделать это, предоставив контекст для селектора jQUery, например $(':title', xdoc.rootElement) или используя XPath (работает в Firefox; якобы есть библиотеки для IE, но я не добился большого успеха с ними). ​​

0 голосов
/ 24 июня 2009

Как насчет этого: Загрузить XML из строки

0 голосов
/ 24 июня 2009

Если вы хотите найти значение специально названных полей (т. Е. Входные данные в форме), что-то вроде этого найдет их для вас:

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

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