新学期が始まる
Jay Allen, Mark Davis, Heidi Housten, and Dan Mohr
Microsoft Corporation
September 3, 2001 日本語版最終更新日 2001年10月18日
ここ北半球では夏は終わりです。
子供たちの新学期が始まります。
近づいてくる秋の気配は、新学期が始まるという気分と一緒になってチームを活気づけています。
私たちはいったいいつになったら大人になるのでしょう。
Jay の娘の新学期が始まったように、
私たちは Jay に仕事を始めてもらいました。
ですので、ここ Web Team Talking の秋は順風満帆になるはずです。
皆さんはより一層満足できることでしょう。
スピットボールと新しいヘアスタイルの話題は横において、
今月は、MSN® Messenger、いくつか手の込んだ JavaScript 機能、
さらにサーバーでの XML データの更新について詳しく調査しています。
また、Q & A 集も用意しています。
知りたいことが出てきたら、
私たちに Web に関する質問を送って ください。
私たちは直ちに作業に取りかかります。
目次
今すぐ満足メッセンジャーを埋め込む
送り返すサーバーの XML を更新する
日付を並べ替えるアルファベット順以外のファイルの並べ替え
Web Team の Q & A
今すぐ満足
Web Team の皆さんへ
msn.com のように MSN Instant Menssenger 埋め込むにはどうすればよいですか。
よろしくお願いします。 Joshua Carroll
Web Team の回答
私たちのさらなる成長を示すには、
MSN Messenger を超える今以上の満足度が必要です。
http://www.msn.com に埋め込まれている IM (Instant Menssenger) 機能は、
DHTML ユーザー インターフェイスを提供するスクリプトと、
メッセンジャー機能を提供する 2 つ の Microsoft ActiveX® コントロールを使って実装されています。
説明を簡単にするために、
仮にユーザーが ログオンしていればメンバ リスト (とその接続状態) を表示し、
ログオンしていなければログオン ボタンを表示する小さなサイドバーをイントラネットのホームページに追加することにしましょう。
以下にサンプルを提供していますが、
この情報を予言するために神のお告げ ((= oracle) 小文字の "o" にご注意ください) が必要だったのではと不思議に思う人のために、
使われている技法の簡単な概要をここに用意しました。
これらのコントロールの役立つ資料がないので、
目的を実現するためにやや探偵のような作業が必要になるでしょう。
まず、いくつか手がかりをつかむために msn.com が使用しているコードを調べます。
これは自信がないからではなく、
このコードを苦労して解読すれば、
2 つのコントロールがどのように機能し、
どのようにコードを書けばいいのかという概念を知ることができるからです。
私たちが使える 2 つ目のツールは OLE View です (そしてこれは非常に役に立ちます)。
OLE View は Microsoft Visual Studio® に同梱されているユーティリティで、
COM オブジェクトの型情報を解析して表示できるという機能があります。
そこで、OLE View を起動し、
2 つのコントロール (MSN Messenger Application と MSN Messenger Object という親しみやすい名前です) を見つけ、
それらを右クリックし、[View type information] をクリックします。
このビューにはオブジェクトで使用されているさまざまなインターフェイスと列挙値が表示されます。
dispinterface というラベルのインターフェイスはすべてスクリプト ベースの呼び出し側で有効なので、
腕まくりをして、コーディングを始めましょう。
最初にコードがすべきことは、
(コントロールのインスタンスが正しく作成されていることを確認した後で)
ユーザーがオンラインかどうかを調べることです。
これは Messenger オブジェクトの LocalState プロパティを確認することによって行います。
このプロパティは、サンプル コードで一部を定義をしている MSTATE 列挙値からの値を返します。
ユーザーがオンラインではない場合は、
Messenger Application の LaunchLogonUI メソッドを呼び出すログオン ボタンを有効にします。
ユーザーが オンラインの場合は、
すべてのメンバを含む DIV 要素を作成する必要があります。
これを実現するには、
既定のリスト (List(0)) の各メンバをすべて繰り返し処理し、
FriendlyName とそれらの現在状態を表す MSTATE 値を両方とも取得し、
その後この情報を含んでいる新しい DIV 要素を作成します。
ユーザーがリスト内の任意のメンバをクリックすることにより、
そのメンバにメッセージを送信できるようにしたいので、
プログラムから onclick イベント ハンドラを新しい DIV 要素に結び付けています。
そのイベント ハンドラ関数 (sendMessage) は、
基本的には Messenger Application の LaunchIMUI メソッドのラッパーです。
LaunchIMUI は目的のメンバをパラメータとして受け取るので、
クリックされた DIV 要素と一致する Messenger Object の既定のリスト内のメンバを調べる必要があります。
これは expando プロパティの典型的な使い方です。
表示用に作成した新しい DIV 要素に、
既定のリストのメンバ インデックスを結び付けます。
このような方法で、onclick ハンドラはインデックスを取得し、
その後 Mesenger Object の一覧から適切なメンバを見つけ、
それを LaunchIMUI に渡すことができます。
このサンプルに含まれている追加機能として、
ページを読み込んだ後でログオンとログオフを処理する機能があります。
これは Messenger Object が呼び出す OnLocalStateChangeResult イベントの処理で行っています。
このイベントは (あまり衝撃的ではありませんが) LocalState プロパティ が変化したときに発生します。
したがって、その応答として、(メンバの UI リストを空にした場合に) オフラインになったかどうか、
または (すべてが正しく同期していることを確かめる簡潔な setTimeout の後で populateContacts を呼び出す場合に) オンラインになったかどうかを確認します。
ActiveX コントロールはスタンドアロンのメッセンジャーの実行中のインスタンスに結び付けられているので、
それによって発生するイベントにも同じように反応してページが更新されます。
そして "おしゃべりはもうたくさん、コードを見せて !" と叫んでいるコンピュータおたくの皆さん、お待たせしました。
<HTML>
<HEAD>
<TITLE>Embedding MSN Messenger Test</TITLE>
<OBJECT CLASSID="clsid:F3A614DC-ABE0-11d2-A441-00C04F795683"
CODEBASE="#Version=2,0,0,83"
CODETYPE="application/x-oleobject" ID="oMsgrObj" WIDTH="0"
HEIGHT="0" OnUserStateChanged="alert();">
</OBJECT>
<OBJECT CLASSID="clsid:FB7199AB-79BF-11d2-8D94-0000F875C541"
CODETYPE="application/x-oleobject"
ID="oMsgrApp" WIDTH="0" HEIGHT="0">
</OBJECT>
<STYLE>
BODY
{
FONT-FAMILY: Verdana, Arial, Helvetica;
FONT-SIZE: 8pt;
}
INPUT
{
FONT-FAMILY: Verdana, Arial, Helvetica;
FONT-SIZE: 8pt;
}
.clsHeading
{
FONT-WEIGHT: bolder;
FONT-SIZE: 10pt;
}
.clsContact
{
PADDING: 2px;
CURSOR: hand;
}
</STYLE>
</HEAD>
<BODY onLoad="body_onLoad();">
<SCRIPT LANGUAGE="JScript">
// 以下は、使用するメッセンジャーの列挙値の定義です。
var MSTATE_OFFLINE = 1;
var MSTATE_ONLINE = 2;
var MSTATE_BUSY = 10;
var MSTATE_BE_RIGHT_BACK = 14;
var MSTATE_IDLE = 18;
var MSTATE_AWAY = 34;
function body_onLoad()
{
// まず、メッセンジャーのコントロールのインスタンスが正しく作成されたことを確認します。
if ("undefined" != typeof(oMsgrObj) && null != oMsgrObj.object && "undefined"
!= typeof(oMsgrApp) && null != oMsgrApp.object)
{
// 正しく作成された場合は、オンラインになっていることを調べ、オンラインであればメンバを UI に設定します。
if (oMsgrObj.LocalState == MSTATE_ONLINE)
{
populateContacts();
}
else if (oMsgrObj.LocalState == MSTATE_OFFLINE)
{
btnLogon.disabled = false;
}
}
else
{
// コントロールのインスタンスが正しく作成されなかった場合、
// ユーザーはメッセンジャーをインストールする必要があるでしょう。
alert("最新版の MSN Messenger をインストールする必要があります !
\n今すぐ http://messenger.msn.com へ !");
}
}
function populateContacts()
{
var oList = oMsgrObj.List(0);
var oContact;
var i;
// メンバ リストを設定するために、既定のリスト コレクションの最後まで
// 繰り返し処理を行い、各メンバの状態を調べて、適切な外観を
// 持つ DIV 要素を UI に追加します
for (i = 0; i < oList.Count; i++)
{
oContact = oList.Item(i);
oNewElement = document.createElement("DIV");
oNewElement.innerText = oContact.FriendlyName;
switch (oContact.State)
{
case MSTATE_ONLINE:
// 何もする必要がありません
break;
case MSTATE_OFFLINE:
oNewElement.innerText += " (Offline)";
oNewElement.style.color = "graytext";
break;
case MSTATE_BUSY:
oNewElement.innerText += " (Busy)";
break;
case MSTATE_BE_RIGHT_BACK:
oNewElement.innerText += " (Be Right Back)";
break;
case MSTATE_IDLE:
oNewElement.innerText += " (Idle)";
break;
case MSTATE_AWAY:
oNewElement.innerText += " (Away)";
break;
default:
oNewElement.innerText += "(Just plain not around!)";
oNewElement.style.color = "graytext";
break;
}
oNewElement.className = "clsContact";
// onclick イベントに応答するために
// プログラム上にイベント ハンドラを設定し、
// 既定のリスト中のメンバ インデックスに値が
// 設定されたメンバの DIV の expando プロパティを
// 定義しています (したがって後で検索できます)
oNewElement.onclick = sendMessage;
oNewElement.setAttribute("CONTACTID", i.toString());
divContacts.appendChild(oNewElement);
}
}
function doLogon()
{
// ログオンするために、メッセンジャーにログオン UI を表示することを要求します
if (oMsgrObj.LocalState == MSTATE_OFFLINE)
{
btnLogon.disabled = true;
oMsgrApp.LaunchLogonUI();
}
}
function sendMessage()
{
// メッセージを送信するために、同様にメッセンジャーにたくさんの作業を
// 要求します (私たちは既定のリストからメッセージをメンバに渡す必要が
// あるだけです)
var nContactID = parseInt(window.event.srcElement.getAttribute("CONTACTID"));
if (!isNaN(nContactID))
{
var oContact = oMsgrObj.List(0).Item(nContactID);
oMsgrApp.LaunchIMUI(oContact);
}
}
</SCRIPT>
<SCRIPT LANGUAGE="JScript" EVENT="onLocalStateChangeResult(hr)" FOR="oMsgrObj">
if (hr == 0)
{
if (oMsgrObj.LocalState == MSTATE_ONLINE)
{
// 現在オンラインです
window.setTimeout("populateContacts();", 3000);
}
else if (oMsgrObj.LocalState == MSTATE_OFFLINE)
{
// 現在オフラインです
divContacts.innerHTML = "";
btnLogon.disabled = false;
}
}
</SCRIPT>
<DIV CLASS="clsHeading">Contacts (click on a contact to send a message!)</DIV>
<DIV ID="divContacts" STYLE="MARGIN-TOP: 8px;
MARGIN-BOTTOM: 8px; BORDER: 1px solid steelblue"></DIV>
<INPUT TYPE="BUTTON" ID="btnLogon" VALUE="Logon" onClick="doLogon();" DISABLED="yes">
</BODY>
</HTML>
送り返す
Web Team の皆さんへ
どうすればクライアントの Web ブラウザで XML を変更し、
その結果の XML を Web サーバーに送信できるのですか ?
Web Team の回答
あなたの Web ブラウザが Microsoft Internet Information Server (IIS) Version 4.0 以降、
または ASP (Active Server Page) テクノロジをサポートしている製品を実行していると仮定します。
Web ブラウザが豊富で、対話的なインターネットの動作をどのように提供しているかを簡単に見直してみましょう。
最も簡潔な形式では、
Web ブラウザが Web サーバーからページを要求し、
返された情報通常は HTML (HyperText Markup Language) ですを処理し、
その結果を表示します。
HTTP (HyperText Transfer Protocol) は、
Web サーバーとブラウザが対話するために使用する言語を定義しています。
また Web ブラウザは、
ユーザーが Web をナビゲートし、
さまざまな種類のメディアを表示できるように、
背後で多くの処理を行っています。
さて、対話的な Web サイトが必要な場合、
ユーザーは Web サーバーにどうやって情報を送るのでしょうか ?
ここでは
Web ブラウザまたは Web アプリケーションから Web サーバーに XML を送信するための数ある方法の中の 2 つを取り上げています。
Web ブラウザは一般的に Web ページの要求に HTTP GET メソッドを使用し、
情報の送信に HTTP POST メソッドを使用します。
ユーザーと Web サーバー間で情報のやり取りを行えるようにする最も簡単な方法は、
HTML FORM 要素を使用することです。
FORM 要素は、
GET メソッドまたは POST メソッドのどちらかを使用してサーバー にデータを送信する方法を提供します。
どんなコントロールがフォーム内に配置されているのかを判断し、
その中で NAME 属性が指定されているコントロールだけがデータを送信します。
たとえば、ユーザーが [送信] ボタンをクリックしたときに、
各コントロールのデータが Web サーバーに送信されます。
以下の例では、
XML データ アイランドに格納されている XML がフォームの一部としてサーバー に送信されます。
XML は、ハード コードにされたもの、
SRC 属性の設定により外部ファイルから読み込まれたもの、
ADO レコードセットから取得されたもの、
SQL Server 2000 から取得されたもの、
XML DOM スクリプト オブジェクト モデルを使用して作成または変更されたもの、
というように非常にさまざまな方法で入手できます。
XML は HTML 要素にバインドしてユーザーに表示できます
(「Binding HTML Elements to Data」をご覧ください)。
フォーム送信に XML データを含めることは、
以下に示すように、
onsubmit イベント ハンドラの隠された INPUT 要素に XML を代入するだけの簡単な作業です。
<FORM ACTION="http://yourserver/form.asp" METHOD="post" NAME="myform"
ONSUBMIT=" myform.mytext.value = myxml.XMLDocument.xml;">
<INPUT TYPE="HIDDEN" NAME="Text" ID="mytext">
<INPUT TYPE="Submit">
</FORM>
<XML ID="myxml">
<root>
<item id="1" name="Item 1"/>
<item id="2" name="Item 2"/>
</root>
</XML>
以下は FORM.ASP ページのコンテンツです。
<%@ language=JScript %>
<%
var xmldom = Server.CreateObject( "Microsoft.XMLDOM" );
var xml = Request.Form( "Text" );
Response.Write( "<XMP>" + xml + "</XMP>" );
%>
注意
この例では便宜上、サーバーは XMP 要素の内部で XML を返します。
この HTML 要素の使用に反対する人もいますが、
HTML 要素と XML 要素をテキストとして表示するという利点があります。
XMLHttpRequest オブジェクトは、
Microsoft Internet Explorer Version 5.0 以降に同梱されている MSXML コンポーネントの一部です。
オブジェクトは Web ページ で作成され、
XML を Web サーバーに送信するために使用されます。
オブジェクトはアプリケーション名として Microsoft.XMLHTTP を指定することによって作成 されます。
通常は Open メソッドを呼び出し、
オプションとしてヘッダ情報を設定し、
Send を呼び出した後、
responseXML プロパティまたは responseText プロパティを確認することになるでしょう。
このオブジェクトを使う利点の 1 つは、
サーバーとブラウザ間でシームレスなデータ転送を利用して、
ページを更新せずに POST を実行できる点です。
XMLHttpRequest オブジェクトは、
(SOAP 要求を使用して) .NET XML Web サービスを呼び出すために Internet Explorer の
Web service behavior によって使用されます。
以下は、Web サーバーに XML ドキュメントを送信する例を示しています。
この例では同期呼び出しを使用していることに注意してください。
同期呼び出しを行うには、
Open メソッドへの 3 番目の引数として true を渡し、
Send メソッドが完了したときに onreadystatechange イベント ハンドラを使用して通知します。
<HEAD>
<script language="JScript">
function PostXml(xmldoc)
{
var xmlhttp = new ActiveXObject( "Microsoft.XMLHTTP" );
xmlhttp.Open( "POST", "http://yourserver/xmlhttp.asp", false );
xmlhttp.Send( xmldoc );
return xmlhttp.responseXML;
}
function ShowResults()
{
var resp = PostXml( myxml.XMLDocument );
mydiv.innerHTML = "<XMP>" + resp.xml + "</XMP>";
}
</script></HEAD>
<BODY>
<BUTTON ONCLICK="ShowResults()">Post XML</BUTTON>
<DIV ID="mydiv"></DIV>
<XML ID="myxml">
<root>
<item id="1" name="Item 1"/>
<item id="2" name="Item 2"/>
</root>
</XML>
以下は、XMLHTTP.ASP ファイルのコンテンツです。
<%@ language=JScript %>
<%
// XML を読み込みます
var doc = Server.CreateObject( "Microsoft.XMLDOM" );
doc.load( Request );
// XML を処理します
// 結果を返します
Response.ContentType = "text/xml";
doc.save( Response );
%>
クライアントで XML を格納することは、
ユーザーの Web サイトに革新的な機能をもたらす状況が数多くあります。
たとえば、頻繁に使用されるデータのキャッシング、ユーザーのパーソナライゼーション、
インライン データの編集などです。
ここでは Web サーバーに XML データを送信する 2 つのメカニズムについてお話してきました。
サーバーでの XML データの処理は ASP テクノロジを使用すると簡単であり、
ASP.NET という新しい機能を使用するとよりいっそう簡単になります。
サーバーは、ファイルやデータベースに情報を保存したり、
XML コンテンツに従って操作を実行するなどの多くの方法で XML を処理することを選択できます。
以下に、この記事の範囲外になりますが、
Web サーバーにデータを送信する別の方法をいくつか挙げます。
- HTTP GET メソッド。これは情報の送信先として要求される URL のクエリ文字列 ('?' の後ろのテキスト) を使用します。
ただし、URL のサイズは 2KB までに制限されています。
- HTTP PUT メソッド。セキュリティに心配な点があります。
- HTML INPUT TYPE=FILE 要素は、ユーザーが選択したファイルのアップロードに使用できます。
- 低レベルの WinInet 関数を直接 ActiveX コントロールまたはアプリケーションから呼び出し、
Web サーバーとの通信をさらに細かく制御します。
- Internet Explorer
Web service behavior を使用して .NET XML Web サービスを呼び出します。
日付を並べ替える
Web Team の皆さんへ
私は特定のフォルダのコンテンツを表示し、
それらのファイルを作成日時順に並べ替えようと努力しています (現在はアルファベット順になっています)。
ASP と FileSystemObject を使ってこれを行う方法はありますか ?
どんなことでも構いません。教えてください。
Matt Pierce
Web Team の回答
あなたに必要だったのは質問することだけでした。
以下にファイル名のコレクショ ンを取得し、
それらを作成日時順に並べ替える FileSystemObject scripting オブジェクトを使用している ASP ページのサンプルを挙げます (ありがとう、Eric !)。
FileSystemObject scripting オブジェクトに関する資料は、
Microsoft Windows Script Technologies site にあります。
GetFolder() メソッドは、
指定したパスのフォルダ オブジェクトを取得するために呼び出します。
フォルダ オブジェクトは、
Enumerator
オブジェクトを使用してアクセスできる files コレクションを含んでいます。
各ファイルはファイル名順に取得されるので、
それらを後で並べ替えられるように配列に代入します。
arr[i++] = {path : fc.item().Path, date : fc.item().DateCreated};
上記に示したあまり使用しない代入構文は、
オブジェクト リテラルとして知られており、
プロパティ指定を表すカンマ区切りのリストで構成されます。
各プロパティ指定は、プロパティ名とそれに続くプロパティ値で構成されます。
オブジェクト リテラル構文は、
path と date の 2 つのプロパティを持つオブジェクトの作成に使用されます。
Array オブジェクトの sort() メソッドを利用すると、
独自の比較関数 sortByDate を指定して並べ替え順を決定できます。
この場合、comparison 関数は作成日時によって 2 つの項目の相対的な順序を示す値を返しますが、
ほかのファイル プロパティで並べ替えるために簡単に変更できます。
<%@ language=JScript %>
<%
function sortByDate(f1, f2)
{
if (f1.date < f2.date)
return -1;
else if (f1.date > f2.date)
return 1;
else
return 0;
}
function showfiles(path)
{
var fso, f, f1, fc, arr, i, s;
fso = new ActiveXObject( "Scripting.FileSystemObject" );
f = fso.GetFolder( path );
// ファイル リストを作成します
arr = new Array();
i = 0;
for ( fc = new Enumerator( f.files ); !fc.atEnd(); fc.moveNext() )
arr[i++] = {path : fc.item().Path, date : fc.item().DateCreated};
// ファイル リストを並べ替えます
arr.sort( sortByDate );
// ファイル リストを表示します
s = "";
for ( i=0 ; i<arr.length ; ++i )
s += arr[i].path + "<br>";
return s;
}
Response.Write( showfiles( Server.MapPath( "." ) ) );
%>
Web Team の Q & A
Web アクセシビリティ
Q: Web サイトをアクセス可能にする方法を教えてください。 (Rob)
A: Microsoft Enable サイトで、
アクセシビリティ Web ガイドライン をご覧ください。
色覚障害を持つ方々への考慮
Q: 色覚障害と Web 開発に関する情報はありますか ? (Becca)
A: Robert Hess の定期コラム More or Hess
の記事「色覚に障害を持っていたとしたら、あなたのサイトは見えるでしょうか ?」をご覧ください。
ビヘイビア
Q: どのような目的で DHTML ビヘイビアが使われるのですか ? (Pierre)
A: MSDN Online Library にビヘイビアに関する優れた概要紹介の
概要記事があります。
また、DHTML Dude の「表を楽しむ」というタイトルのコラムでもこのトピックを扱っています。
イントラネット認証
Q: ドメイン名とパスワードを使用する Web サイトに対して、
企業ユーザーを自動的に認証させる方法を教えてください。 (Paul)
A: Internet Explorer で、
[ツール] メニューの [インターネット オプション] をクリックし、
[セキュリティ] タブをクリックします。
さらに、[レベルのカスタマイズ] をクリックして [ユーザー認証] までスクロール ダウンし、
[イントラネット ゾーンでのみ自動的にログオンする] をオンにします。
会社の IT グループが設定を変更していなければ、このオプションは既定でオンになっているはずです。
Web Team
|