2005年08月06日

JavaScript版Referer Hound

 作った。このところ日記の更新が少なかったのは、これにかまけていたせいだ。

 Referer Houndの原理については、すでにさんざん解説したので繰り返さない。外部ドメインのサーバと通信する手法も、Google AdSenseでおなじみである。

 ただし、iframe要素ではなく、内容自体を挿入するのは珍しい。

 これはReferer Houndの設計・実装上の重要なポイントではないし、手間もかかっていない(1日で動くようになり、3日で完成した)が、応用がきくので、興味のある向きも多いかと思う。解説しよう。

 基本は、こちらに書いてあるとおりだ。JavaScript中で、document.writeやDOMでscript要素を書き込むと、それが実行される。そのscript要素のsrc属性は、外部ドメインでもいい。そしてもちろん、src属性のなかに、クエリ文字列を入れることができる。

 HTMLの中に静的に書き込んであるJavaScriptを、Aとする。Aが実行されたときに動的に読み込まれ実行されるJavaScriptを、Bとする。もちろんBはさらに別のJavaScriptを動的に読み込んで実行できるわけだが、Referer Houndはそこまではしていないので、AとBだけで話を進めよう。

 BはJavaScriptだが、サーバで動的に生成される。Referer Houndでは、XMLをXSLTにかけてJavaScriptに変換している。このJavaScriptを実行すると元のXMLが生成されるというわけだ。こう書くとまるで魔法だが、たいしたことはない。参考までに、Referer Houndで使われているXSLTを載せておく。これはスキーマにかかわらず使えるはずである。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="text" version="1.0" encoding="UTF-8"/>
	<xsl:template match="/">
{
	var domDocument = Sarissa.getDomDocument();

	function dctn(text) {
		return domDocument.createTextNode(text);
	};
	function dce(en) {
		return domDocument.createElement(en);
	};
	var ce = dce('root');
	var e;
		<xsl:apply-templates/>
	sendRPCDone(ce.firstChild);
}
	</xsl:template>
	<xsl:template match="text()">
	ce.appendChild(dctn("<xsl:value-of select="."/>"));
	</xsl:template>
	<xsl:template match="@*">
	ce.setAttribute("<xsl:value-of select="name()"/>", "<xsl:value-of select="."/>");
	</xsl:template>
	<xsl:template match="*">
	e = dce("<xsl:value-of select="name()"/>");
	ce.appendChild(e);
	ce = e;
		<xsl:apply-templates select="@*"/>
		<xsl:apply-templates/>
	ce = ce.parentNode;
	</xsl:template>
</xsl:stylesheet>

 なおSarissaとは、JavaScriptのDOM実装である。AはBを読み込む前にSarissaを読み込んでいる。また、このXSLTに食わせる前に、要素内容と属性内容に含まれるダブルクォーテーションとバックスラッシュをエスケープ処理しなければならない。

 Aはキャッシュが利くので、動的に生成されない部分はできるだけAに詰め込みたい。だからBは実行後、生成されたXMLを引数にして、Aで定義された関数を呼び出す。上のXSLTでは、sendRPCDoneがそれである。この関数が、渡されたXMLをHTMLに変換して書き込む。

 以上が、原理のすべてである。

 この手法にこれといった名前はまだないようなので、私がつける。「Cross Domain Ajax」、略して「XDA」だ。

 なお、JavaScriptの常として、原理の単純さからは想像もつかないような地獄めぐりをさせられる。プロジェクトの要にAjaxやXDAを置くのは大博打だ、と忠告しておく。

Posted by hajime at 2005年08月06日 08:28
Comments

こんにちは、RefererHoundを使わせてもらってるものです。
バグかどうかわからないのですが、
RefererHoundでうまくいっていない所があったのでここに書かさせてもらいます。
(RefererHoundのページに報告フォームが見当たらなかったので)

どうも、RefererHoundを設置しているページが、
%などが含まれたURLEncodeされているURLであった場合、
Refererのリストが表示されていない気がするのです。

Posted by: Yuanying at 2005年08月09日 17:24

通知ありがとうございます。
そのとおりでした。現在では修正されていると思います。

Posted by: 中里一 at 2005年08月09日 19:32