レベル: 中級 Mark Pruett (mark.l.pruett@dom.com), System Architect, Dominion
2008年 3月 11日 この連載の第 2 回では、Mark Pruett が Ajax (Asynchronous JavaScript + XML) による天気バッチの手法をさらに 2 つ紹介します。両方とも XSLT (Extensible Stylesheet Language Transformation) を使用してフォーマットを変換する手法ですが、一方ではサーバー・サイド、もう一方ではブラウザーで XSLT を使用します。
第 1 回目の記事で説明したように、この連載で規定している問題は、Web ページに簡単に挿入できる天気バッジを作成するというものです。この天気バッジは Ajax の手法により構成され、米国 NWS (National Weather Service) が提供するデータを使用します。NWS データは XML フォーマットで提供され、15 分ごとに更新されます。
この連載では、天気バッジを実装する際の 4 つの手法を検討しています。第 1 回で紹介した 1 番目の手法は、まず Apache Web サーバーのプロキシー規則を使って NWS にアクセスし、その XML データをブラウザーに取得しました。それから JavaScript コードを使用して DOM から必要なデータを抽出し、HTML にフォーマット変換して表示するという方法を取っています。
今回の記事では 2 番目と 3 番目の手法に目を向けます。この 2 つの手法には 1 つの共通点があります。それは、どちらも XSLT を使用することです。
XSLT
 |
よく使われる頭字語
- DOM: Document Object Model
- HTML: Hypertext Markup Language
- XML: Extensible Markup Language
- XSLT: Extensible Stylesheet Language Transformation
|
|
XSLT は、XML に対してクエリーを実行して他のフォーマットに変換するための言語です。私の気象データでは、まさにこれが問題の核心となっています。このデータは XML としてパッケージ化されていますが、それよりもユーザー (そしてブラウザー) に使いやすい形にしたいからです。さらに NWS データには天気バッジに必要な情報以外の情報も大量に含まれています。そのため、必要なデータ項目だけを抽出する何らかの手法が必要です。XSLT でなら、この 2 つの要件に対処することができます。
XSLT についての解説はこの記事の対象外なので、XSLT について詳しく知りたい方は developerWorks の記事「XSLTはどのような言語か」(「参考文献」を参照) を読んでください。
XSLT 言語が他の多くのコンピューター言語と異なる点は、その構文が妥当な XML であるという点です。このことが C、Java™、Perl、Python などの言語を使用している読者にとって多少、混乱の種となるかもしれません。
今回紹介する 2 番目と 3 番目の天気バッチに対する手法ではいずれも XSLT を使うので、まずはこの XSLT を使用する部分を紹介することにします。その後、この XSLT を使用した部分がソリューション全体のなかにどのように収まるのかを説明します。
XSLT を使用したデータのフォーマット変換
まず始めに、NWS の XML データ・フォーマットについて検討します。リスト 1 に簡略化した例を示します。
リスト 1. NWS のサンプル XML データ・ファイル KNGU.xml (要約)
<?xml version="1.0" encoding="ISO-8859-1"?>
<current_observation version="1.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation=
"http://www.weather.gov/data/current_obs/current_observation.xsd">
<credit>NOAA's National Weather Service</credit>
<credit_URL>http://weather.gov/</credit_URL>
<image>
<url>http://weather.gov/images/xml_logo.gif</url>
<title>NOAA's National Weather Service</title>
<link>http://weather.gov</link>
</image>
<suggested_pickup>15 minutes after the hour</suggested_pickup>
<suggested_pickup_period>60</suggested_pickup_period>
<location>Norfolk, Naval Air Station, VA</location>
<station_id>KNGU</station_id>
<latitude>36.94</latitude>
<longitude>-76.28</longitude>
<observation_time>
Last Updated on Jan 7, 2:53 pm EST
</observation_time>
<observation_time_rfc822>
Mon, 7 Jan 2008 14:53:00 -0500 EST
</observation_time_rfc822>
<weather>Fair</weather>
<temperature_string>74 F (23 C)</temperature_string>
<temp_f>74</temp_f>
<temp_c>23</temp_c>
<relative_humidity>34</relative_humidity>
<wind_string>From the Southwest at 9 Gusting to 18 MPH</wind_string>
<wind_dir>Southwest</wind_dir>
<wind_degrees>240</wind_degrees>
<visibility_mi>10.00</visibility_mi>
<icon_url_base>
http://weather.gov/weather/images/fcicons/
</icon_url_base>
<icon_url_name>
skc.jpg
</icon_url_name>
<disclaimer_url>http://weather.gov/disclaimer.html</disclaimer_url>
<copyright_url>http://weather.gov/disclaimer.html</copyright_url>
<privacy_policy_url>http://weather.gov/notice.html</privacy_policy_url>
</current_observation>
|
リスト 1 のなかで私の興味の対象となるのは強調表示したデータだけです。そのため XSLT プログラムでは、最初の仕事としてこれらの必要な要素を抽出しなければなりません。その上で、データのサブセットを HTML に再フォーマット設定し、ブラウザーに表示できるようにすることが2 番目の仕事となります。
リスト 2 に、この 2 つの仕事を行う際に使われる XSLT プログラムを示します。
リスト 2. 気象データの XSLT プログラム、weather2html.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />
<xsl:template match="/current_observation">
<center>
<b><xsl:value-of select="location" /></b><br/>
<xsl:value-of select="weather" /><br/>
<xsl:variable name="icon_url_base" select="icon_url_base"/>
<xsl:variable name="icon_url_name" select="icon_url_name"/>
<img border='0' src='{$icon_url_base}{$icon_url_name}'/><br/>
<xsl:value-of select="temperature_string" /><br/>
Wind: <xsl:value-of select="wind_string" /><br/>
Humidity: <xsl:value-of select="relative_humidity" />%<br/>
Visibility: <xsl:value-of select="visibility_mi" /> miles<br/>
<br/><span style='font-size: 0.8em; font-weight: bold;'>
<xsl:value-of select="observation_time" /></span><br/>
</center>
</xsl:template>
</xsl:stylesheet>
|
まずは以下の行に注目してください。
<xsl:output method="html" />
|
この行が XSLT プロセッサーに、出力はデフォルトの XML フォーマットではなく、HTML であるという情報を与えます。
XSLT プログラムは HTML と XML を混ぜ合わせたように見えますが、それがまさに、このプログラムの実態です。
<xsl:
で始まる XML 要素はいずれも XSLT 言語のステートメントで、それ以外のテキストはその文字通りに出力されます。
その一例として、以下の行を見てください。
<b><xsl:value-of select="location" /></b><br/>
|
xsl:value-of 要素が XSLT プロセッサーに指示している内容は、XML 入力ファイルで location 要素を探し、この要素の値を抽出して xsl:value-of タグの代わりにその値を出力することです。その結果、出力は以下のようになります。
XSLT プロセッサー
Perl や Ruby などの他のプログラミング言語と同様、XSLT は言語インタープリターを介して実行します。この言語インタープリターは XSLT プロセッサーと呼ばれることもよくあります。しかし XSLT の目的は汎用プログラミング言語とは違い、単一の XML データ・ファイルを変換することです。そのため大抵の XSLT プロセッサーに必要となる入力は、XSLT プログラムと変換対象の XML ファイルの 2 つとなります。
Linux® ディストリビューションの多くには、xsltproc という名前のコマンドライン XSLT プロセッサーが含まれています。これは他の同様のツールと同じく、XSLT スクリプトをデバッグして微調整するための変数です。
xsltproc が受け取ることを想定しているパラメーターは、XSLT プログラム、そして XSLT プログラムの実行対象となる XML の 2 つです。例えば、バージニア州ノーフォーク海軍航空基地の NWS XML データを KNGU.xml ファイルにダウンロードしてあるとします (KNGU は、第 1 回で説明した 4 文字からなる固有のステーション ID です)。この場合、以下のコマンドを使ってリスト 2 の XSLT プログラムをテストすることができます。
xsltproc weather2html.xsl KNGU.xml
|
XSLT プロセッサーは weather2html.xsl に記述された変換を入力ファイルである KNGU.xml に適用し、その結果を標準出力に書き出します。リスト 3 に、この出力を記載します。
リスト 3. KNGU.xml の XSLT 処理による出力
<center>
<b>Norfolk, Naval Air Station, VA</b><br>
Fair<br>
<img border="0"
src="http://weather.gov/weather/images/fcicons/skc.jpg"><br>
57 F (14 C)<br>
Wind: From the West at 7 MPH<br>
Humidity: 58%<br>
Visibility: 7.00 miles<br>
<br>
<span style="font-size: 0.8em; font-weight: bold;">
Last Updated on Oct 12, 7:53 am EDT
</span>
<br>
</center>
|
手法その 2: サーバーでの XSLT
この XSLT の手法を天気バッジの問題に適用しようと思います。手法その 2 では、サーバー・サイド・スクリプトによって NWS サーバーからデータをプルし、XSLT を使用して XML を HTML に変換してから、変換後の HTML スニペットをブラウザーに送り返します。ブラウザーが行う作業は、このスニペットをそのまま DIV タグに挿入するだけに過ぎません。
図 1 に、この手法で使用するデータ・パイプラインを示します。NWS サーバーから私のサーバーへのデータ・フローでは、サーバー・サイド・スクリプトが XML を HTML に変換します。パイプラインの終わりにあるのはブラウザーで、ブラウザーが HTML を受信して Web ページに挿入します。
図1. 手法その 2 のデータ・パイプライン
ここで必要となるのは、XSLT 変換を実行することのできるサーバー・サイド・プログラムです。今回、このプログラムはリスト 4 に示すように Perl で記述しますが、他の言語でも同じく簡単に実装することができます。このスクリプトは、ブラウザーでの XMLHttpRequest 呼び出しによって起動されます。Ajax の JavaScript コードがサーバー・サイド・スクリプトに送信する単一のパラメーターは、NWS サーバーから XML データ・ファイルを取得するために必要な 4 文字の NWS ステーション ID です。
リスト4. weather_xml2html.cgi の Perl スクリプト
#!/usr/bin/perl
use strict;
my $DATA_DIR = "/var/www/html/xml_weather/data";
my $XSL_FILE = "$DATA_DIR/weather2html.xsl";
my $XSLTPROC = "/usr/bin/xsltproc";
my $HTTP_BIN = "/usr/bin/wget -q -O - ";
my $URL_FORMAT = "http://www.nws.noaa.gov/data/current_obs/%s.xml";
# Get the NOAA location key:
my $location = $ENV{QUERY_STRING};
# Minimal sanity check of the location key:
if ($location !~ /^[\d\w]{4}$/) {
print "Content-type: text/html\n\n";
print "Unknown location ($location).\n";
exit 1;
}
# Build URL:
my $url = sprintf ($URL_FORMAT, $location);
# Build Command:
my $cmd = "$HTTP_BIN '$url' 2> /dev/null | $XSLTPROC $XSL_FILE - ";
print "Content-type: text/html\n\n";
open (my $IPIPE, "$cmd |");
while (<$IPIPE>) {
print $_;
}
close $IPIPE;
|
私の Apache Web サーバーがリスト 4 のスクリプトを実行すると、Apache QUERY_STRING 環境変数がこのスクリプトに 4 文字のステーション ID を提供します。
この Perl スクリプトは、xsltproc と wget という 2 つの外部コマンドを使用します。xsltproc は前述したコマンドライン XSLT プロセッサーです。もう一方の wget は無料のユーティリティー (Free Software Foundation から入手可能) で、ほとんどの Linux ディストリビューションにはプリインストールされています。wget は Web から Web ページ (またはその他の Web リソース) を取得できるため、この Perl スクリプトでは wget を使って NWS サーバーから XML ファイルを取得しています。
この Perl スクリプトが構成するコマンド・パイプラインを Liunx コマンドラインで実行する場合には、以下のようになります。
/usr/bin/wget -q -O - http://www.nws.noaa.gov/data/current_obs/KNGU.xml \
| /usr/bin/xsltproc /var/www/html/xml_weather/data/weather2html.xsl -
|
 |
外部プログラムの使用について
プログラマーによっては、外部プログラムを使用してこの簡単な Ajax による Web サービスを実装することに驚きを覚えるかもしれません。CPAN (Comprehensive Perl Archive Network) リポジトリーには何千もの Perl モジュールが含まれており、そのなかのいくつかは wget や xsltproc の代わりに使用できるからです。しかし、この 2 つのユーティリティーを使うことによって、weather_xml2html.cgi スクリプトは Python や Ruby といった他の言語にも移植しやすくなります。それは、ほとんどのスクリプト言語では、外部プログラムの出力をスクリプトにパイプ接続できるからです。実際には、使用する言語で利用可能なライブラリーまたはモジュールを使用することをお勧めします。
|
|
上記のコマンドによる出力は、Perl スクリプトに読み込まれて標準出力に送信されます。このスクリプトを起動したのは、ブラウザーの JavaScript コードによる XMLHttpRequest であることを思い出してください。したがって、この出力はレスポンスとしてブラウザーに送り返されます。
手法その 1 で使用した方法とは異なり、Apache のプロキシー規則は必要ありません。インテリジェント・プロキシーとして機能するこの weather_xml2html.cgi スクリプトを私のサーバー上に常駐させることによって、第 1 回で説明した同一ドメインの問題を回避しています (「参考文献」を参照)。
サーバーが返すのは天気バッジのフォーマット設定済み HTML なので、クライアント・サイドの天気バッジ・ライブラリーが行う作業はほとんどありません。リスト 5 に、この 2 番目の手法に必要な JavaScript コードを記載します。
リスト 5. weather_badge() の weather_badge_intel_proxy.js 実装
function weather_badge (nws_id, div_name) {
var ajax = new Ajax
("/cgi-bin/xml_weather/weather_xml2html.cgi?",
nws_id,
"GET",
function (req) {
var div = document.getElementById (div_name);
div.innerHTML = req.responseText;
}
);
ajax.request ();
}
|
このバージョンの weather_badge() に必要なのは、サーバー・スクリプトを (適切な NWS ステーション ID を指定して) 呼び出し、それによって返された HTML をその innerHTML プロパティーを使って対象の DIV タグに挿入することだけです。
長所と短所
この手法では、処理の大部分が Web サーバーで行われることになります。そのため、サーバーにアクセスするユーザーが少ない場合、あるいはサーバーのメモリー容量と CPU サイクルに大量の余裕がある場合には、この手法が功を奏します。
同様に、ユーザーが処理能力の低い古いデスクストップ・マシンで実行していることがわかっている場合にも、この手法が理にかなっています。ブラウザーが行う作業はほとんどなく、ブラウザーはリクエストを送信して、サーバーが重たい処理を行ってくれるのを待てばいいだけの話だからです。
手法その 3: クライアント・サイドの XSLT
3 番目の天気バッジ実装でも XSLT を使用しますが、今回はブラウザーで XSLT 処理を行います。使用するプログラムは前と同じ weather2html.xsl XSLT プログラム (リスト 2) です。図 2 に、この手法で使用するデータ・パイプラインを示します。
図2. 手法その 3 のデータ・パイプライン
主要なブラウザー (Microsoft® Windows® Internet Explorer®、Firefox、および Opera) はいずれも何らかの形で XSLT 処理をサポートします。具体的には、Firefox と Opera では XSLTProcessor オブジェクトを実装する一方、Internet Explorer では Document モデルを拡張して XSLT 処理を操作します。
リスト 6 は、手法その 3 の weather_badge() 実装です。この手法では、手法その 1 の場合と同じく、ブラウザーが NWS サーバーにアクセスできるようにするために Apache Web プロキシー規則を配置する必要があります (前にも説明したように、Ajax アプリケーションがアクセスできるデータは、元の Web ページを配信したサーバーのデータだけだからです。この同一ドメインの問題についての詳細は、第 1 回を参照してください)。
リスト 6. weather_badge() の weather_badge_cs_xslt.js 実装
function weather_badge (nws_id, div_name) {
// Get the XML file from the server.
var ajax = new Ajax ("/nws_currobs/" + nws_id + ".xml", "", "GET", null);
ajax.setAsync (false);
ajax.request ();
var xml_doc = ajax.req.responseXML;
// Get the XSLT from the server.
ajax = new Ajax ("/xml_weather/data/weather2html.xsl", "", "GET", null);
ajax.setAsync (false);
ajax.request ();
var xsl_doc = ajax.req.responseXML;
var div = document.getElementById (div_name);
// Use object detection to find out if we have
// Firefox/Mozilla/Opera or IE XSLT support.
if (typeof XSLTProcessor != "undefined") {
var xsl_proc = new XSLTProcessor ();
xsl_proc.importStylesheet (xsl_doc);
var node = xsl_proc.transformToFragment (xml_doc, document);
div.innerHTML = "";
div.appendChild (node);
}
else if (typeof xml_doc.transformNode != "undefined") {
div.innerHTML = xml_doc.transformNode (xsl_doc);
}
else {
div.innerHTML = "XSLT not supported in browser.";
}
}
|
手法その 1 では、NWS サーバーから XML ファイルを取得しなければなりませんでした。今回の新しい手法では、私自身のサーバーから XSLT ファイルを取得する必要もあります。 リスト 6 の前半が、この 2 つの新しいファイルを weather_badge() 関数に組み込むために必要なコードです。これらのファイルは XMLHttpRequest に対して、xml_doc および xsl_doc という JavaScript Document オブジェクトとして返されます。
weather_badge() 関数の後半は、XSLT フォーマット変換を適用します。この変換の処理方法は Internet Explorer と他のブラウザーとで異なるため、実行中のブラウザーのタイプを判別する必要があります。そのために使用するのがオブジェクト検出です。JavaScript の typeof 演算子を使って、変換を実行するために必要なオブジェクトの有無をチェックします。
XSLTProcessor が定義されていれば、Firefox または Opera ブラウザーを使っていることになります。その場合には、新規 XSLTProcessor オブジェクトをインスタンス化し、このオブジェクトに XSLT スタイル・シートをインポートします。それからこのオブジェクトの transformToFragment メソッドを使って XML 気象データをフォーマット変換します。このメソッドが返すのは、HTMLテキストではなく文書のフラグメントです。つまり、最初の 2 つの手法で行ったように、innerHTML を使って結果を DIV タグに挿入することはできません。しかし、これに対するソリューションは以前の手法とほとんど同じくらいに簡単です。appendChild を使用すれば、結果の文書フラグメントをページの DOM ツリーに挿入することができます。
一方、XSLTProcessor ではなく transformNode メソッドが定義されている場合には、JavaScript プログラムが Internet Explorer で実行されているということです。その場合に必要なのは以下のたった 1 行のコードで、このコードが XSLT フォーマット変換を実行し、その結果を DIV タグに挿入します。
div.innerHTML = xml_doc.transformNode (xsl_doc);
|
長所と短所
この 3 番目の手法では、最初の 2 つの手法の要素を使用しています。それは、Apache Web プロキシーが XML を追加処理するためにブラウザーに返すという点、そして XSLT が XML から HTML への実際の変換を処理するという点です。
ブラウザー内部で XSLT プロセッサーを起動するということは、DOM ツリーから必要なデータ要素に直接アクセスするだけに過ぎない手法 1 に比べ、コンピューターの能力を一層駆使することになります。この単純な例では、コンピューターの処理時間が余計にかかってもユーザーは気付かないでしょう。しかし XML が大規模なものであったり、XSLT 変換が複雑な場合には、ブラウザーが結果を大量出力している間、ユーザーが許容できないほどの遅延が発生する可能性があります。
逆を返せば、大規模な XML ファイルの複雑な DOM ツリーを手作業で辿っていかなければならないようなコードは、作成するのが大変な (しかもコードの保守はもっと大変な) JavaScript コードになってしまう可能性があるということです。
さらに、ユーザーが使用しているブラウザーとコンピューターの種類も考慮しなければなりません。十分なメモリー容量とプロセッサー処理能力を備えたハイエンドのワークステーションを使用しているのか、あるいは古い力不足のマシンを使用しているのかどうかによって、複雑な JavaScript XSLT 処理を行うことが果たしてアプリケーションに適しているかどうかが決まります。
まとめ
連載最終回となる次回の記事では、この問題に対する最後の手法を検討します。それは、今まで紹介した手法のどれと比較しても根本的に異なるソリューションです。このあまりの違いの大きさに、Ajax の手法ではないという異議さえ出てくるかもしれません。この最後のソリューションは、今までの 3 つのソリューションをてこずらせてきた同一ドメインの問題を回避しますが、まったく新しい問題ももたらします。4 つすべての手法を説明し終えたところですべての手法を比較するとともに、他にも数多くある手法のいくつかについても触れる予定です。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Sample code for this series | x-xmlajax.zip | 194KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
-
IBM 試用版ソフトウェア: developerWorks から直接ダウンロードできる試用版ソフトウェアで、次の開発プロジェクトを構築してください。
議論するために
著者について
記事の評価
|