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

     2023-02-24     241

关键词:

【中文标题】使用 jQuery 解析远程内容的最佳实践是啥?【英文标题】:What is the best practice for parsing remote content with jQuery?使用 jQuery 解析远程内容的最佳实践是什么? 【发布时间】:2010-11-05 07:31:41 【问题描述】:

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

jQuery 只能选择存在于字符串中的 XHTML 元素,前提是它们通常在 W3C 规范中的 div 中被允许;因此,我对选择 <title><script><style> 等内容感到好奇。

根据 jQuery 文档:

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

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

因此,既然我们已经确定 jQuery 不提供执行此操作的方法,我将如何选择这些元素?例如,如果您能告诉我如何选择远程页面的标题,那就太好了!

谢谢,皮特

【问题讨论】:

好时机!我现在也可以为此使用答案。 我注意到即使尝试解析 RSS 提要也会出现此问题。例如,您不能在 标记中抓取 或 。 【参考方案1】:

我建议您暂时退出 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);
          
    );
  

不要乱用 iframe 等。

【讨论】:

我在这和使用正则表达式之间纠结。由于我要求最佳实践,我选择了这个答案。【参考方案2】:

如果您创建一个 iframe 来临时存储文档,这只是一个想法 - 在 FF/Safari 中测试过 - 似乎可行。当然,如果你正在这样做,那么只使用 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();
      
    );
  );

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

【讨论】:

为什么我一开始没有想到 iframe?这很棒!我看到的唯一可能的问题是,如果您必须从另一个站点获取文档,iframe 可能无法工作。我没试过,但我认为跨域脚本策略会禁止与源的任何交互。 这行得通,但问题是寻找最佳实践而不是 hack。 @zinigor 这是一个有争议的问题,因为您甚至无法发出跨域 AJAX 请求。 @Josh Stodola 是的,但我不是在谈论 AJAX 请求。您可以简单地编辑 iframe 的 src 属性并使其指向另一个站点,并且它不必位于同一个域中。这就是同源政策限制将限制所有交互的地方。 @JoshStodola 有一个解决方法,您可以使用 curl,抓取内容并回显它,然后对该文件发出 ajax 请求。【参考方案3】:

灵感来自this answer,但有延迟:

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(点击“运行”)

【讨论】:

【参考方案4】:

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

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

);

【讨论】:

@Ben Koehler :我想使用这段代码,但我很惊讶,它在 IE8 上不起作用(没有在 IE7 上测试),在 Chrome 2.x 和 FF 3 上没问题。 x【参考方案5】:

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

查看解释和内联 cmets 以了解其工作原理以及为什么必须这样制作。

当然,这不能用于检索跨域内容,因为您要么必须通过自己的脚本代理调用,要么考虑像 flXHR (Cross-Domain Ajax with 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) 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 中,没有 createXMLDocumentbeforeSend 函数,整个事情都可以工作。

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

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 对象上的该功能,因此如果运行错误回调并且错误为 parsererror,我必须自己生成 XMLDocument。

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>

【讨论】:

【参考方案6】:

无耻地复制并改编自我的另一个答案 (Simple jQuery ajax example not finding elements in returned 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;

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

【讨论】:

应用简单的线性搜索肯定不是最佳做法。 当然不是——但该示例显示了一种方法,您也可以从正文之外的外部文档中选择标签,这是 jQuery 无法做到的。 javascriptkit.com/dhtmltutors/treewalker.shtml 可能有用吗? 另外,我很确定这会成为 jQuery 在获取 <meta> 等标签时遇到的相同问题的受害者。阅读关于 htmlOwnerDocument 的问题中的链接 gnarf,不确定您的意思 - 我测试了代码,它有效吗? jQuery 并不真正获取 HTML,只是获取“数据”。非 jQuery 函数将该数据解析为标签,然后将其中之一返回给 jQuery。如果你遇到了一个 jQuery 不喜欢的标签,你总是可以用相同的函数解析它的内容。【参考方案7】:

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

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

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

【讨论】:

谢谢,但这不是我想做的。 我看到你重新编辑了你的问题。如果您想处理整个 XHTML 片段,那么像 Resig 的微模板之类的东西可以为您指明正确的方向……请参阅 ejohn.org/blog/javascript-micro-templating 不确定您的任何一个回答如何甚至可以间接回答我的问题。我没有对这个问题进行重大修改。【参考方案8】:

这个怎么样:Load XML from string

【讨论】:

【参考方案9】:
$.get('yourpage.html',function(data)
    var content = $('<div/>').append(data).find('#yourelement').html();
);

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

【讨论】:

【参考方案10】:

在将 XML 字符串解析为 XML DOM 后,我会直接在其上使用 jQuery(您可以通过为 jQUery 选择器提供上下文来实现此目的,例如 $(':title', xdoc.rootElement) 或使用 @987654325 @(在 Firefox 中工作;据说有 IE 库,但我没有取得很好的成功)。

【讨论】:

来自问题:“既然我们已经确定 jQuery 不提供这样做的方法” ...

解析服务器:用远程数据更新本地存储的最佳方法是啥

...】:2016-03-0910:53:04【问题描述】:我有一个用例,我必须使用在我的解析服务器中所做的更改来更新本地存储中的一个类。我已经删除了解析服务器中的一些条目,并希望在用户设备上 查看详情

使用objective-c块时避免泄漏的最佳实践是啥?

】使用objective-c块时避免泄漏的最佳实践是啥?【英文标题】:Whatarethebestpracticestoavoidleakswhenusingobjective-cblocks?使用objective-c块时避免泄漏的最佳实践是什么?【发布时间】:2013-05-0717:59:13【问题描述】:我已经使用块有一段时间... 查看详情

使用 ML Studio API 开发 CD/CI 的最佳实践是啥?

】使用MLStudioAPI开发CD/CI的最佳实践是啥?【英文标题】:WhatisthebestpracticetodevelopCD/CIwhenyouuseMLstudioAPIs?使用MLStudioAPI开发CD/CI的最佳实践是什么?【发布时间】:2019-01-2703:15:48【问题描述】:在我们的后端开发过程中,我们有两个... 查看详情

CSS3 - 性能最佳实践是啥? [关闭]

...javascript性能、瓶颈和最佳实践。在我的最新项目中,我使用CSS3和javascript/jquery的后备来实现基本动画和效果,例如悬停,并且有兴趣进一步试验 查看详情

NSURLSession 的最佳实践是啥?

...0-12-2309:53:48【问题描述】:先订阅我的应用:大部分场景使用AFNetworking,一小部分场景使用NSURLSession.sharedSession或者新建一个NSURLSession。使用一个URLProtocol实例处理几乎 查看详情

使用程序集属性的最佳实践是啥?

】使用程序集属性的最佳实践是啥?【英文标题】:WhatarethebestpracticesforusingAssemblyAttributes?使用程序集属性的最佳实践是什么?【发布时间】:2010-09-0821:46:48【问题描述】:我有一个包含多个项目的解决方案。我正在尝试通过链... 查看详情

使用 AutoLayout 的最佳实践是啥?

】使用AutoLayout的最佳实践是啥?【英文标题】:WhatisbestPracticestouseAutoLayout?使用AutoLayout的最佳实践是什么?【发布时间】:2014-02-0611:20:22【问题描述】:从iOS7开始,我一直在寻找标准的GUI设计模式。在我之前的两个应用程序中... 查看详情

使用 UIStoryboards 时的最佳实践是啥?

】使用UIStoryboards时的最佳实践是啥?【英文标题】:WhatisthebestpracticewhenusingUIStoryboards?使用UIStoryboards时的最佳实践是什么?【发布时间】:2012-06-1312:15:28【问题描述】:使用故事板已经有一段时间了,我发现它们非常有用,但... 查看详情

使用 webpack 导入 angularjs 的最佳实践是啥?

】使用webpack导入angularjs的最佳实践是啥?【英文标题】:Whatisthebestpracticeforimportingangularjsusingwebpack?使用webpack导入angularjs的最佳实践是什么?【发布时间】:2015-04-2306:28:28【问题描述】:你如何一起使用Webpack和AngularJS,模板加... 查看详情

RxSwift:使用 DisposeBag 的最佳实践是啥?

】RxSwift:使用DisposeBag的最佳实践是啥?【英文标题】:RxSwift:WhatisthebestpracticetouseDisposeBag?RxSwift:使用DisposeBag的最佳实践是什么?【发布时间】:2018-08-0513:32:53【问题描述】:现在我需要根据配置API更改应用程序主题(颜色)... 查看详情

在 .Net 中使用扩展方法的最佳实践是啥?

】在.Net中使用扩展方法的最佳实践是啥?【英文标题】:WhatarethebestpracticesforusingExtensionMethodsin.Net?在.Net中使用扩展方法的最佳实践是什么?【发布时间】:2010-09-0509:54:18【问题描述】:我已经看到这些被以各种方式使用,并被... 查看详情

DAO(数据访问对象)最佳实践 - 我看到的示例同时使用 DAO 和服务对象,这里的最佳实践是啥?

】DAO(数据访问对象)最佳实践-我看到的示例同时使用DAO和服务对象,这里的最佳实践是啥?【英文标题】:DAO(dataaccessobject)bestpractices-examplesIseeuseaDAOandaServicesobjectboth,whatisthebestpracticehere?DAO(数据访问对象)最佳实践-我看到的... 查看详情

使用 TeamCity 合并语义版本控制的最佳实践是啥

】使用TeamCity合并语义版本控制的最佳实践是啥【英文标题】:What\'stheBestPracticeforincorporateSemanticVersioningusingTeamCity使用TeamCity合并语义版本控制的最佳实践是什么【发布时间】:2012-09-1107:46:37【问题描述】:TeamCity是一个很棒的CI... 查看详情

在多个项目中使用相同模型的最佳实践是啥?

】在多个项目中使用相同模型的最佳实践是啥?【英文标题】:WhatisthebestpractiseofusingsameModelonseveralprojects?在多个项目中使用相同模型的最佳实践是什么?【发布时间】:2018-12-1121:04:17【问题描述】:我使用Sequelize和PostgreSQL数据... 查看详情

在 vue 组件中使用样式的最佳实践是啥?

】在vue组件中使用样式的最佳实践是啥?【英文标题】:Whatsthebestpracticetousestylesinvuecomponents?在vue组件中使用样式的最佳实践是什么?【发布时间】:2020-10-1118:31:31【问题描述】:我正在使用vuecli创建项目,但我的样式出现“错... 查看详情

使用 Xcode 构建用户界面的最佳实践是啥?

】使用Xcode构建用户界面的最佳实践是啥?【英文标题】:WhatarethebestpracticesinbuildinguserinterfacewithXcode?使用Xcode构建用户界面的最佳实践是什么?【发布时间】:2015-07-2107:47:19【问题描述】:我正在使用Xcode和AutoLayout为应用程序设... 查看详情

在 JSON 中编码日期的最佳实践是啥?

...“最佳”格式是什么?数据属性应该:只需很少或不需要解析即可转换为Date()对象可以在JSON表示本身中排序返 查看详情

使用共享库版本支持不同 ABI 的最佳实践是啥?

】使用共享库版本支持不同ABI的最佳实践是啥?【英文标题】:WhatisthebestpracticeforsupportingdifferentABIswithasharedlibraryrelease?使用共享库版本支持不同ABI的最佳实践是什么?【发布时间】:2018-05-2003:42:55【问题描述】:我相信MS在MSVC... 查看详情