使用 jQuery 解析远程内容的最佳实践是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1034881/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 10:28:05  来源:igfitidea点击:

What is the best practice for parsing remote content with jQuery?

jqueryhtml-parsing

提问by slypete

Following a jQuery ajax call to retrieve an entire XHTML document, what is the best way to select specific elements from the resulting string? Perhaps there is a library or plugin that solves this issue?

在 jQuery ajax 调用以检索整个 XHTML 文档之后,从结果字符串中选择特定元素的最佳方法是什么?也许有一个库或插件可以解决这个问题?

jQuery can only select XHTML elements that exist in a string if they're normally allowed in a div in the W3C specification; therefore, I'm curious about selecting things like <title>, <script>, and <style>.

jQuery 只能选择存在于字符串中的 XHTML 元素,前提是 W3C 规范中的 div 中通常允许这些元素;因此,我很好奇选择喜欢的东西<title><script><style>

According to the jQuery documentation:

根据 jQuery 文档:

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

The HTML string cannot contain elements that are invalid within a div, such as html, head, body, or title elements.

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

HTML 字符串不能包含 div 中无效的元素,例如 html、head、body 或 title 元素。

Therefore, since we have established that jQuery does not provide a way to do this, how would I select these elements? As an example, if you can show me how to select the remote page's title, that would be perfect!

因此,既然我们已经确定 jQuery 没有提供这样做的方法,那么我将如何选择这些元素?举个例子,如果你能告诉我如何选择远程页面的标题,那就完美了!

Thanks, Pete

谢谢,皮特

采纳答案by David Burrows

Instead of hacking jQuery to do this I'd suggest you drop out of jQuery for a minute and use raw XML dom methods. Using XML Dom methods you would can do this:

我建议您暂时退出 jQuery 并使用原始 XML dom 方法,而不是使用 jQuery 来执行此操作。使用 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);
          }
    });
  }

No messing about with iframes etc.

没有搞乱 iframe 等。

回答by gnarf

Just an idea - tested in FF/Safari - seems to work if you create an iframe to store the document temporarily. Of course, if you are doing this it might be smarter to just use the src property of the iframe to load the document and do whatever you want in the "onload" of it.

只是一个想法 - 在 FF/Safari 中测试 - 如果您创建一个 iframe 来临时存储文档,似乎可以工作。当然,如果您正在这样做,那么使用 iframe 的 src 属性加载文档并在它的“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();
      }
    });
  });

I had to append the iframe to the body to get it to have a .contentWindow.

我必须将 iframe 附加到正文以使其具有 .contentWindow。

回答by abernier

Inspired from this answer, but with deferred:

灵感来自这个答案,但有延迟:

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

And smoke it with:

并用以下方法吸烟:

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

LIVE DEMO(click 'Run')

现场演示(单击“运行”)

回答by jitter

This works. I just split up the building blocks for better readability.

这有效。我只是拆分了构建块以获得更好的可读性。

Check the explanation and the inline comments to grasp the workings of this and why it has to be made like this.

检查解释和内联注释以了解它的工作原理以及为什么必须这样做。

Of course this can't be used to retrieve cross-domain-content for that you either have to proxy the calls through a script of yours or think about integration something like flXHR (Cross-Domain Ajax with Flash)

当然,这不能用于检索跨域内容,因为您要么必须通过您的脚本代理调用,要么考虑像flXHR(带 Flash 的跨域 Ajax)之类的集成

call.html

呼叫.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.jsis (jQuery 1.3.2 uncompressed) test.htmla valid XHTML-Document

jquery.js是(jQuery 1.3.2 未压缩) test.html一个有效的 XHTML 文档

xmlDoc.js

xml文档

// 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

输出.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

准备好.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 the whole thing works without the createXMLDocumentand the beforeSendfunction.

在 Opera 中,整个事情都可以在没有createXMLDocumentbeforeSend功能的情况下工作。

The extra trickery is needed for Firefox (3.0.11) and IE6 (can't test IE7, IE8, other browsers) as they have a problem when the Content-Type:returned by the server doesn't indicate that it's xml. My webserver returned Content-Type: text/html; charset=UTF-8for test.html.In those two browsers jQuery called the errorcallback with textStatussaying parsererror. Because in line 3706 in jQuery.js

Firefox (3.0.11) 和 IE6(无法测试 IE7、IE8、其他浏览器)需要额外的技巧,因为当Content-Type:服务器返回的结果不是 xml时,它们会出现问题。我的网络服务器返回Content-Type: text/html; charset=UTF-8fortest.html.在这两个浏览器中 jQuery 调用error回调并textStatusparsererror. 因为在 jQuery.js 的第 3706 行

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

datais being set to null. As in FF and IE the xhr.responseXMLis null. This happens because they don't get that the returned data is xml (as Opera does). And only xhr.responseTextis set with the whole xhtml-code. As data is null the line 3708

data被设置为空。与在 FF 和 IE 中一样,该xhr.responseXML值为空。发生这种情况是因为他们没有得到返回的数据是 xml(就像 Opera 一样)。并且仅xhr.responseText使用整个 xhtml 代码进行设置。由于数据为空,第 3708 行

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

throws an exception which is catched in line 3584 and status is set to parsererror.

抛出一个异常,该异常在第 3584 行捕获,状态设置为parsererror

In FF I can solve the problem by using the overrideMimeType()function before sending the request.

在FF中,我可以通过overrideMimeType()在发送请求之前使用该函数来解决问题。

But IE doesn't support that function on the XMLHttpRequest-object so I have to generate the XMLDocument myself if the error-callback is run and the error is parsererror.

但是 IE 不支持 XMLHttpRequest 对象上的该函数,因此如果运行错误回调并且错误为parsererror.

example for test.html

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>

回答by Ben Koehler

How about some quick tag renaming?

一些快速的标签重命名怎么样?

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

});

回答by MSpreij

Shamelessly copied and adapted from another of my answers (Simple jQuery ajax example not finding elements in returned HTML), this fetches the HTML of the remote page, then the parseHTML function creates a temporary div element for it and puts the lot inside, runs through it, and returns the requested element. jQuery then alerts the text() inside.

无耻地复制并改编自我的另一个答案(简单的 jQuery ajax 示例未在返回的 HTML 中找到元素),这将获取远程页面的 HTML,然后 parseHTML 函数为其创建一个临时 div 元素并将该批次放入其中,运行它,并返回请求的元素。jQuery 然后提醒里面的 text() 。

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

To get several items out or a list of script tags, say, I think you'd have to improve the parseHTML function, but hey - proof of concept :-)

要获取多个项目或脚本标签列表,例如,我认为您必须改进 parseHTML 功能,但是嘿 - 概念证明:-)

回答by timbo

If you wanted to find the value of specifically named fields (i.e. the inputs in a form) something like this would find them for you:

如果您想查找特定命名字段(即表单中的输入)的值,则类似以下内容会为您找到它们:

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

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

回答by Svante

How about this: Load XML from string

怎么样:从字符串加载 XML

回答by Michael Ekstrand

After parsing the XML string into an XML DOM, I'd either use jQueryon it directly (you can do this by providing a context to the jQUeryselector, such as $(':title', xdoc.rootElement)or using XPath(works in Firefox; there are supposedly libraries for IE but I haven't had good success with them).

解析XML字符串转换成之后XML DOM,我要么用jQuery它直接(您可以通过提供上下文的做这个jQUery选择,如$(':title', xdoc.rootElement)或使用XPath在Firefox(的作品;还有所谓的IE浏览器库,但我没有他们取得了很好的成功)。

回答by Paul

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

You can also simply temporarily wrap inside a div. You don't even need to add it to the DOM.

您也可以简单地暂时包裹在 div 中。您甚至不需要将它添加到 DOM。