XHTMLドキュメント全体を取得するためのjQuery ajax呼び出しの後、結果の文字列から特定の要素を選択する最良の方法は何ですか?おそらく、この問題を解決するライブラリまたはプラグインがありますか?
jQueryは、W3C仕様のdivで通常許可されている場合にのみ、文字列に存在するXHTML要素を選択できます。したがって、<title>
、<script>
、<style>
などを選択することに興味があります。
JQueryのドキュメントによると:
http://docs.jquery.com/Core/jQuery#htmlownerDocument
HTML文字列には、html、head、body、title要素など、div内で無効な要素を含めることはできません。
したがって、jQueryがこれを行う方法を提供しないことを確立したので、これらの要素をどのように選択しますか?例として、リモートページのタイトルを選択する方法を教えていただければ完璧です。
ありがとう、ピート
これを行うために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);
}
});
}
Iframeなどをいじる必要はありません.
ドキュメントを一時的に保存するための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();
}
});
});
.contentWindowを取得するには、iframeを本文に追加する必要がありました。
この答え からインスパイアされましたが、延期されました:
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 ([実行]をクリック)
簡単なタグ名の変更はどうですか?
$.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());
}
});
これは機能します。読みやすくするために、構成要素を分割するだけです。
説明とインラインコメントを確認して、この仕組みと、なぜこのようにする必要があるのかを理解してください。
もちろん、これを使用してクロスドメインコンテンツを取得することはできません。そのため、スクリプトを使用して呼び出しをプロキシするか、または 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.jsis(jQuery 1.3.2 uncompressed)test.html有効なXHTML-Document
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
関数なしですべてが機能します。
サーバーから返された_Content-Type:
_がxmlであることを示さない場合、問題が発生するため、Firefox(3.0.11)とIE6(IE7、IE8、その他のブラウザーをテストできません)には追加のトリックが必要です。 Webサーバーが_Content-Type: text/html; charset=UTF-8
_に対して_test.html.
_を返しました。これらの2つのブラウザーでは、jQueryがerror
コールバックを呼び出し、textStatus
はparsererror
と言いました。 jQuery.jsの3706行目から
_data = xml ? xhr.responseXML : xhr.responseText;
_
data
はnullに設定されています。 FFとIE _xhr.responseXML
_はnullです。これは、返されたデータがxml(Opera )そして、_xhr.responseText
_だけがxhtml-code全体で設定されます。データはnullなので、行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>
_
私の答えの別のものから恥知らずにコピーして適応させました( 返されたHTMLで要素が見つからない単純なjQuery ajaxの例 )、これによりリモートページの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関数を改善する必要があると思いますが、ちょっと-概念実証:-)
これはどうですか: XMLを文字列からロード
XML文字列を_XML DOM
_に解析した後、それに対してjQuery
を直接使用します($(':title', xdoc.rootElement)
などのjQUery
セレクターにコンテキストを提供するか、XPath
を使用してこれを行うことができます(機能します) Firefoxには、おそらくIEのライブラリがありますが、私はそれらで十分に成功していません)。
具体的に名前が付けられたフィールド(つまり、フォームの入力)の値を検索したい場合は、次のようにしてそれらを見つけることができます。
var fields = ["firstname","surname", ...."foo"];
function findFields(form, fields) {
var form = $(form);
fields.forEach(function(field) {
var val = form.find("[name="+field+"]").val();
....
$.get('yourpage.html',function(data){
var content = $('<div/>').append(data).find('#yourelement').html();
});
Div内で一時的にラップすることもできます。 DOMに追加する必要すらありません。