クライアント上の "DXML": Internet Explorer 5、データ アイランド、および XMLDOM オブジェクト
George Young Microsoft Corporation
January 18, 2000
日本語版最終更新日 2000 年 11 月 17 日
編集注: George Young による次回のコラムの掲載は延期されました。
この記事のサンプル コードのダウンロード
このシリーズの他の記事
"DXML": 目次を XML から DHTML へ変換する (April 26, 1999)
"DXML" Redux: XML から Dynamic HTML メニューを構築する (May 24, 1999)
"DXML" in Action: サイトへの DHTML メニューおよび TOC の実装 (June 28, 1999)
"DXML" のグローバル化 : ローカライズと XML/DHTML メニュー (August 9, 1999)
Y2K 問題も大した事態に至らずに、無事やり過ごせたようですね。みなさまに 1900 年の新年のお祝いを申し上げます。
組織内での Internet Explorer 5 の標準化が進むにつれ、Internet Explorer 5 に固有のソリューションへの関心が高まってきています。
私 (そして編集者) は前世紀の 8 月に "Dynamic XML" シリーズ の 最終回 を掲載したつもりでしたが、あれ以来かなり多数の読者の方々から、XML で生成されたメニューをクライアント上の HTML ページに直接レンダリングする方法を尋ねる電子メールが送られてきました。本シリーズのこれまでの記事では、クライアント上ではなくサーバー上で HTML を生成する方法に焦点を当ててきました。しかし、組織内での Internet Explorer 5 の標準化が進むにつれ、Internet Explorer 5 固有のソリューションへの関心が高まりつつあるようです。
昔からこのコラムを読んできた方は、XML からの Dynamic HTML の生成を扱った一連の記事のことを覚えていらっしゃるでしょう ("DXML" という名前はここから付けられました)。このシリーズでは、Web 開発に関するトピックへのリンクの階層的なセットを記述しているXML ファイル ("webdev.xml") を、TOC と、MSDN Online サイトで使われているのと似た DHTML メニューの両方として、XSL を使ってレンダリングしました。
図 1. DHTML メニュー
この記事では、これまでの記事でメニューの生成に使用してきたのと同じ XML、XSL、CSS、およびJScript® ファイルを使用します。DHTML と XSL の実装については、すでに詳しく説明しているので、ここではスペースを節約するために情報とソース コードを再掲することはしません。シリーズの第 2 回と第 3 回の記事、「"DXML" Redux: XML から Dynamic HTML メニューを構築する 」 と 「"DXML" in Action: サイトへの DHTML メニューおよび TOC の実装」 を読んでいない方、または最近になって読み直していない方は、先に進む前に目を通しておくことをお勧めします。
今月は、クライアント上で XML にアクセスするいくつかの方法と、変換された HTML の出力をレンダリングするいくつかの方法について説明します。また、データ バインドの話題もいくつか取り上げます。いつもと同じく、読者からのコメントと質問を歓迎します。ぜひご意見をお寄せください。
- XMLDOM オブジェクトによる XML へのアクセス
- データ アイランドによる XML へのアクセス
- document.write() による HTML の出力
- outerHTML による HTML の出力
- XML DSO による XML データのバインド
- XSL による擬似データ バインド
XMLDOM オブジェクトによる XML へのアクセス
クライアント上で、スクリプトを使って、関連する XML ファイルを HTML 文書に明示的にロードすることができます。このためには、Microsoft.XMLDOM ActiveX® オブジェクトをインスタンス作成し、ロードします。この処理の構文は、サーバー上の Active Server Pages (ASP) ページで XML データをロードする ために使った構文とほぼ同じですが、インスタンス作成には Server.CreateObject() ではなく new ActiveXObject() を使用する点と、ファイルを取得するために Server.MapPath() を使用する必要がない点が異なります。サーバー上での処理と同様に、(エラーを防ぐために) XML 文書が完全にロードされてから実行を再開するように、asyncに、レンダリングの方法にいくらか影響が出ます。ここでは、サーバーに関する記事で詳しく説明したエラー チェックは省略しています。実際の環境では必ずエラー チェックを行ってください。
<SCRIPT LANGUAGE="JScript">
var oMenuXml = new ActiveXObject("Microsoft.XMLDOM");
oMenuXml.async = false;
oMenuXml.load("webdev.xml");
var oMenuXsl = new ActiveXObject("Microsoft.XMLDOM");
oMenuXsl.async = false;
oMenuXsl.load("menus_1.xsl");
</SCRIPT>
リスト 1. XMLDOM オブジェクトを使って XML および XSL データを文書にロードする
XML から DHTML への実際の変換とレンダリングについては、すぐ後で説明します。ここではまず、XML データを文書にロードするもう 1 つの方法を説明しておきましょう。
データ アイランドによる XML へのアクセス
XML を HTML 文書にロードするもう 1 つのクリーンな方法は、XML データ アイランドです。この XML 要素を使用して XML を HTML 文書にロードする方法は 2 つ考えられます。(ページ上の) インライン XML と、外部文書からの取り込みです。
XML データを直接にインラインで指定するには、要素開始タグの <XML> と要素終了タグの </XML> で囲みます。この方法は、プロトタイピングを行っているときにサンプルの XML データを手軽に入力したい場合、あるいは外部ファイルに対する依存関係をなくしたい場合に便利です。
<XML ID="xmlData">
<DATA>
<DATUM>some data</DATUM>
<DATUM>some more data</DATUM>
</DATA>
</XML>
リスト 2. データ アイランドの中のインライン XML
また、XML 要素の SRC 属性を使って、外部ファイルに含まれている XML データを参照することもできます。この方法は、今回の DHTML メニューのように、データを複数の文書で共有している場合に便利です。
<XML ID="xmlMenuData" SRC="webdev.xml"></XML>
リスト 3. 外部ファイルを参照する XML データ アイランド
XSL は XML に他ならないので、XSL スタイル シートは別のデータ アイランドに格納しておくことができます。その後、DHTML メニューを生成するために必要なすべてのデータを取り込みます。
<XML ID="xmlMenuData" SRC="webdev.xml"></XML>
<XML ID="xmlMenuStyle" SRC="menus.xsl"></XML>
リスト 4. データ アイランドの中の文書への XML と XSL の取り込み
XMLDOM オブジェクトでアクセスされる XML 文書と同様に、XML データ アイランドは実際に XML をブラウザ内にレンダリングするわけではありません。文書にデータを取り込んで、データの操作が可能な状態にするだけです。
データ アイランドを使用するにせよ、スクリプト内で XMLDOM オブジェクトを使用するにせよ、文書への XML および XSL データのロードはこれで完了します。次は、XML を HTML としてレンダリングする 2 つの方法について説明します。変換された出力を document.write() を使って HTML ストリームに書き込む方法と、outerHTML を使って文書内の既存の「トークン」要素を置き換える方法です。
document.write() による HTML の出力
変換された XML を document.write() を使って HTML 文書 に出力するためには、メニューを表示したいページ上の場所に <SCRIPT> ブロックを配置します。 1 つの文で、ID 属性によって参照される XSL 文書による XML 文書の変換と、ページへの出力の両方が実行されます。
XSL 変換を行うためには、transformNode() を実行する前に XML と XSL のデータが完全にロードされている必要があるので、このアプローチは XML へのアクセスに XMLDOM オブジェクトを使用している場合にしか使用できません。オブジェクトの async プロパティを false に設定したため、Internet Explorer は処理を先に進める前に、XML 文書を完全にロードしようと試みます。一方、データ アイランドは非同期的なので、文書のコンテンツを出力するときに、データの準備ができていると仮定することはできません。
<SCRIPT LANGUAGE="JScript">
var oMenuXml = new ActiveXObject("Microsoft.XMLDOM");
oMenuXml.async = false;
oMenuXml.load("webdev.xml");
var oMenuXsl = new ActiveXObject("Microsoft.XMLDOM");
oMenuXsl.async = false;
oMenuXsl.load("menus_1.xsl");
</SCRIPT>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JScript">
document.write(oMenuXml.transformNode(oMenuXsl.documentElement));
</SCRIPT>
リスト 5. データ アイランドから変換された XML を document.write() を使って出力する方法
この document.write() のシナリオでは、HTML を生成する menus_1.xsl ファイルに 1 つの修正を加えています。ONMOUSEOVER および ONMOUSEOUT 属性で呼び出される個々の関数について、それが存在するかどうかをテストしているのです。これにより、接続の遅延のために、スクリプト関数のロードが終わる前に HTML のレンダリングが開始されてしまった場合に、スクリプト エラーが発生するのを防ぐことができます。
Internet Explorer 5 ユーザーは、ここで XMLDOM document.write() のサンプルを見ることができます。
outerHTML による HTML の出力
第 2 のアプローチ、つまり outerHTML を使ってトークン要素を置き換えるという方法は、1つの点を除いて document.write() とよく似ています。Internet Explorer は、XSL ファイルに含まれているリンクされたスクリプトとスタイル情報を問題なく document.write() で出力することができますが、これは innerHTML または outerHTML を使用している場合にはうまく行きません。リンク先の情報が読み込まれないのです。このため、リンクされたスタイルまたはスクリプト ファイルは、XSL ファイルではなく、実際の HTML そのものに取り込まなくてはなりません。これは少し面倒な方法ですが、正常に動作します。
「トークン」要素の <DIV ID="divMenuToken"> を作成し、その outerHTML を、XSL 変換によって作成された HTML に設定します。さらに、われわれは非同期的なデータ アイランドの中のデータをもとにしてレンダリングを行うので、 transformNode() を実行し、出力をトークン要素の outerHTML に設定する前に、document.onload() イベント が発生するのを待たなくてはなりません。このためには、文書の onload() イベントに自動的にバインドされる document.onload() という名前の関数を作成します。
<LINK REL="stylesheet" TYPE="text/css" HREF="menus.css" />
<SCRIPT LANGUAGE="JScript" SRC="menus.js"></SCRIPT>
<SCRIPT LANGUAGE="JScript">
function window.onload()
{
divMenuToken.outerHTML = xmlMenuData.transformNode(xmlMenuStyle.documentElement);
}
</SCRIPT>
</HEAD>
<BODY>
<XML ID="xmlMenuData" SRC="webdev.xml"></XML>
<XML ID="xmlMenuStyle" SRC="menus_2.xsl"></XML>
<DIV ID="divMenuToken"></DIV>
リスト 6. outerHTML を使ってデータ アイランドから変換された XML を出力する方法
HTML サンプル コードの先頭に、リンクされたスタイルおよびスクリプト ファイルが置かれていることに注意してください。これらは、これまでの document.write() サンプルでは XSL ファイルに入れられていたものです。ここで使用している menus_2.xsl という XSL スタイル シートは、document.write() サンプルで使用していた menus_1.xsl スタイル シートから、スタイルおよびスクリプト ファイルへのリンクを削除したものです。
Internet Explorer 5 ユーザーは、 ここでデータ アイランドの outerHTML サンプルを見ることができます。
これで、DHTML メニューを生成するために使われる XML データを参照する方法が 2 つあることがわかりました。スクリプト内の XMLDOM オブジェクトを使う方法と、XML データ アイランドを使う方法です。また、これをクライアント上でレンダリングする方法にも、document.write() と outerHTML の 2 つがあります。
| XML データ アクセス |
HTML レンダリング |
| XMLDOM オブジェクト |
document.write() outerHTML/innerHTML |
| XML データ アイランド |
outerHTML/innerHTML |
図 2. データ アクセスと HTML レンダリングのアプローチ
XML DSO による XML データのバインド
これで、クライアント上での DHTML メニューのレンダリングの説明を終えたので、XML データをクライアント上で表示するための別のアプローチについて説明しましょう。これはメニューの表示よりも表形式のデータの表示に適しています。 XML Data Source Object (DSO) を使って、TABLE に直接データをバインドするという方法です。
Internet Explorer では、XML データ アイランド (およびその他の DSO) からのデータを、一定の HTML 要素のセットに直接にバインドすることができます。これらの要素とデータ バインド一般については、「Binding HTML Elements to Data」を参照してください。ここでは、XML メニュー データを <TABLE> にバインドし、スクリプティングなしでブラウザ内に XML を直接にレンダリングする方法を簡単に説明します。
データ コンシューマとして使用した場合、<TABLE> 要素は反復エージェントになり、データセット全体を自動的に反復します。ここでは、DATASRC 属性を使って、<TABLE> に対して DSO (XMLデータ アイランド) の ID を指定し、DATAFLD 属性を使って、どの「フィールド」または nodeName にバインドするのかを識別します。
ただし、データバインドされた <TABLE> が自動的に行ってくれない処理が 2 つあります。XML 文書の中の正しいレベルに自動的に入れ子にすることはできず、またそれ単独では再帰的な処理は行えません。これらの処理は明示的に指定する必要があります。
webdev.xml という文書では、1 つのレベルに TYPE 属性を持つ TOPICS があります。次のレベルには、それぞれ TITLE および URL childNode を持つ TOPIC ノードがあります。このような入れ子構造のため、個々の TOPICS ノードのすべてのデータを取得するためには、TOPIC ノード レベルのための別の TABLE を明示的に指定する必要があります。
<XML ID="xmlMenuData" SRC="webdev.xml"></XML>
<TABLE BORDER ID="tblMenus" DATASRC="#xmlMenuData" DATAFLD="TOPICS">
<TR VALIGN="top">
<TD><SPAN DATAFLD="TYPE"></TD>
<TD>
<TABLE DATASRC="#xmlMenuData" DATAFLD="TOPIC">
<TR>
<TD><A DATAFLD="URL"><SPAN DATAFLD="TITLE"></A></TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE>
リスト 7. TOPICS およびT OPIC データのデータバインド <TABLE> への取得
入れ子になった <TABLE> は、DATASRC 属性では同じ XML データ アイランドを参照していますが、DATAFLD 属性としては TOPIC ノードをポイントしていることに注意してください。<TABLE> バインディング エージェントがこの深いレベルに達したら、TOPIC の TITLE childNode 値を、TITLE をポイントした DATAFLD を持つ <SPAN> に入れることができます。TOPIC ノードが XML ツリーの中でさらに 1 レベル深い位置にある場合には、これを取得するために第 3 の TABLE が必要となります。
図 3. XML データ アイランドへのデータ バインドの第 1 バージョン
これで、入れ子レベル (またはマスタ - 細部) の問題は解決されました。しかし、これで終わりではありません。TOPICS ノード (TYPE="XML") それ自身が TOPICS ノードを含んでおり、また反復エージェントは自動的に再帰処理を行わないので、TOPIC <TABLE> と並行して、完全な <TABLE> 構造の新たなインスタンス (下のコードで緑色になっている部分) を明示的に追加する必要があります。これは、Internet Explorer に対し、トップレベル TOPICS の childNode である TOPICS のデータをレンダリングするように指示しています。
<XML ID="xmlMenuData" SRC="webdev.xml"></XML>
<TABLE BORDER ID="tblMenus" DATASRC="#xmlMenuData" DATAFLD="TOPICS">
<TR VALIGN="top">
<TD><SPAN DATAFLD="TYPE"></TD>
<TD>
<TABLE DATASRC="#xmlMenuData" DATAFLD="TOPIC">
<TR>
<TD><A TARGET="_new" DATAFLD="URL"><SPAN DATAFLD="TITLE"></A></TD>
</TR>
</TABLE>
<TABLE BORDER DATASRC="#xmlMenuData" DATAFLD="TOPICS">
<TR VALIGN="top">
<TD><SPAN DATAFLD="TYPE"></TD>
<TD>
<TABLE DATASRC="#xmlMenuData" DATAFLD="TOPIC">
<TR>
<TD><A TARGET="_new" DATAFLD="URL"><SPAN DATAFLD="TITLE"></A></TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE>
</TD>
</TR>
</TABLE>
次に、出力のスクリーン ショットを示します。XML 文書の TOPICS TYPE="XML" ノードのデータが正しくレンダリングされています。
図 4. XML データ アイランドへのデータ バインドの第 2 バージョン
Internet Explorer 5 ユーザーは、ここでデータ バインドのサンプルを見ることができます
XSL による擬似データ バインド
表形式のデータ バインドは (単純なデータ構造であれば) 比較的簡単ですが、データが複雑になるにつれて急速にその複雑さの度合を増していきます。さらに、再帰処理がサポートされていないということは、データを使用する前に、そのデータがどのような構造を持っているのかを知っておかなくてはならないということを意味しています。代わりの方法として、XSL の再帰処理サポートを利用すれば、XML データを任意の深さまで (その深さについての知識がなくても) レンダリングすることができます。また、XSL では、データ バインドでは不可能な、<A HREF> などの出力属性を持つデータを追加することができます。
データ バインドは、特定のバインド HTML 要素の更新を「ネイティブ」にサポートしているので、XSL はまったく同等の代替物とはなりえません。しかし、必要なのが表形式のデータのレンダリングだけなのであれば、特にそのデータが複雑ならば、XSL は興味深い代替テクニックとなります。
次に、上のデータ バインドの例とまったく同じ「外見」を生成する XSL スタイル シートを示します。これはかなり基本的なスタイル シートで、"TOPICS"ノード用に 1 つ、"TOPIC" ノード用に 1 つ、合わせて 2 つのメイン テンプレートを含んでいます。これまでの記事で説明したように、XSL は TOPICS テンプレートの <xsl:apply-templates select="TOPIC" /> と <xsl:apply-templates select="TOPICS" /> の行によって無制限の再帰処理を行うことができます。webdev.xml の "XML" ノードのように、"TOPICS" ノードが少なくとも1つの "TOPICS" childNode を持っている限り、ドリルダウンは自動的に処理されます。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<TABLE BORDER="1">
<xsl:apply-templates select="TOPICLIST/TOPICS" />
</TABLE>
</xsl:template>
<xsl:template match="TOPICS">
<TR>
<TD><xsl:value-of select="@TYPE" /></TD>
<TD>
<TABLE><xsl:apply-templates select="TOPIC" /></TABLE>
<TABLE BORDER="1"><xsl:apply-templates select="TOPICS" /></TABLE>
</TD>
</TR>
</xsl:template>
<xsl:template match="TOPIC">
<TR VALIGN="top">
<TD>
<A TARGET="_new">
<xsl:attribute name="HREF">
http://msdn.microsoft.com<xsl:value-of select="URL" />
</xsl:attribute>
<xsl:value-of select="TITLE" />
</A>
</TD>
</TR>
</xsl:template>
</xsl:stylesheet>
Internet Explorer 5 ユーザーは、ここで XSL による擬似データ バインドのサンプルを見ることができます。
まとめ
これで、XML と XSL から DHTML ユーザー インターフェイスをレンダリングする方法を扱う "DXML" シリーズの最新にして最後の記事は終わりです。もちろん、読者のみなさんからのコメントに触発されて、次の記事が書かれる可能性はあります。それまでは、みなさんが Web アプリケーションの中で XML と DHTML をどのように使っているかを、電子メールでわれわれに教えてください。まだサンプル コードをダウンロードしていない方は、この記事で取り上げているすべてのサンプルが含まれているので、ぜひ試してください。
では、ハッピー コーディング!
George Young は、Internet Explorer チームの開発者であり、以前は Windows 2000、MSDN Online サイト、および Site Builder Network サイトの開発を手がけました。余暇には、Windows Media Player でメキシコのラジオ局に耳を傾け、ニューオーリンズからワシントン州レドモンドへキャデラックで通勤しています。
|