ホーム > X-Plus > XML Square >  デベロッパーズコーナー  >  DOMプログラミング講座

この記事を送る はてなブックマークに追加する BuzzurlにブックマークBuzzurlにブックマーク Yahoo!ブックマークに登録
テキストリンクコードを取得する

デベロッパーズコーナー:DOMプログラミング講座 III(5)

2002年04月26日作成 

DOM プログラミングレッスン
第5回:サーバー間通信を利用する(その1)
(株)日本ユニテック
太田 純

<この記事はDigital Xpress 2001 Vol.5(10-11月号)に掲載されたものです>

今回はWebアプリケーションで他のサーバーとXMLデータを送受信する方法について扱います。

XMLデータをPOSTする

今回考慮するのは、XMLデータを他のサーバーへPOSTする方法です。図1をご覧ください。


図1 XMLデータを他のサーバーへPOST

Webサーバーとデータサーバーがイントラネット上でつながっている場合はさまざまな方法でのアクセスが可能ですが、ここで紹介する方法はデータサーバーにHTTPでアクセスできれば実現することができます。当然のことながら、HTTPでXMLメッセージを送って操作を行うのは、直接ファイル操作をしたりCOMを使用したりする場合と比べて性能面で優れた方法とは言えませんが、セキュリティを保ちつつメッセージ交換を行う方法として注目されています。

MSXML 3.0では、XMLデータを他のサーバーへ送るために便利に使えるオブジェクトとしてServerXMLHTTPが用意されています。リスト1にServerXMLHTTPを利用したサンプルコードを示します。ServerXMLHTTPオブジェクトのインターフェース名はIServerXMLHTTPRequestとなっています。このサンプルは、リスト2で示すHTMLフォーム(図2参照)からPOSTされたデータを使用してXMLデータを組み立て、他のサーバーにXMLメッセージをPOSTし、結果を取得します。今回はATLでサーバーオブジェクトを作成し、メソッドやプロパティの呼び出しには#importで生成されるエラーチェック付きバージョンを使用しました(注1)。


図2 リスト2のHTMLファイル(enq.htm)の表示例

リスト1でコードしたオブジェクトを呼び出すASPをリスト3に示します。リスト1のRegist関数がこのASPから呼び出すメソッドで、GetDictItemText関数は内部的に使用する関数です。RequestオブジェクトからHTMLのフォームデータを取り出す方法については本論からそれますので詳しくは扱いません。慣れないと難しいのでこの2つの関数およびリスト2のHTMLを比較して参考になさってください。

Regist関数内の強調表示した部分を見るとわかるとおり、ServerXMLHTTPオブジェクトを作成したら、

  1. openメソッドで送り先のURLを指定
  2. setRequestHeaderメソッドでFORMデータとして送ることを指定
  3. sendメソッドでXMLデータを送出

の順に実行します。XML SDKのヘルプによれば、sendメソッドの引数にはDOMDocumentオブジェクトのIDispatchポインタを渡すことができると記述されていますが、これはMSXML 3.0のバグでうまく動作しない場合があります。xmlプロパティで文字列を取り出してからsendメソッドに渡してください。詳細は、Article ID: Q282102 PRB: ServerXMLHTTP Object Adds Content-Type Header with XML Dataで説明されています(注2)。

sendメソッドを実行したら、正常に実行されたかどうかをstatusプロパティで確認します。statusプロパティにはHTTPリターンコードが入りますので、400以上599以下ならばエラーであることがわかります。エラーの場合は、statusTextプロパティでエラーメッセージを取り出すことができます。

正常に実行された場合は、IServerXMLHTTPRequestのプロパティで結果を取り出します。以下の4つのプロパティのどれかを使うことができます。

IServerXMLHTTPRequestのプロパティ
内容
responseBody VT_UI1のSAFEARRAY
responseStream IStreamオブジェクト
responseText 文字列
responseXML DOMDocumentオブジェクト

responseXMLプロパティを使えばDOMのオブジェクトを取得できますから、ここからさらにデータを抽出したり、XSLTで整形したりするのに便利でしょう。リスト2のサンプルでは単にクライアントにそのまま送っています。

ServerXMLHTTP オブジェクトは、このようにXMLデータを他のサーバーとやり取りするのに便利な機能を提供してくれていますが、サポートされているプラットフォームに制限があります。現状では

  • Internet Explorer 5.01以上を載せたWindows NT 4.0
  • Windows 2000

でのみサポートされています。したがって、Windows 9x系のプラットフォーム上で動かす可能性のあるクライアントアプリケーションから直接XMLデータをサーバーへ送りたい場合には適用できません。

次回はデータサーバー側のコードを紹介し、このアプリケーションを完成させる予定です。お楽しみに。

リスト1 ServerXMLHTTPを使用する

STDMETHODIMP CEnqSender::Regist(BSTR DataServer) // 引数DataServer:送り先URL
{
        IXMLDOMDocument2Ptr pDoc1;
        HRESULT hr = pDoc1.CreateInstance(CLSID_DOMDocument);
        if(FAILED(hr))
                return hr;
        try {
                pDoc1->async = VARIANT_FALSE;
                pDoc1->loadXML(wszTemplate);

                CComPtr<IRequestDictionary> pDict;
                hr = m_piRequest->get_Form(&pDict);
                if(FAILED(hr))
                        _com_issue_errorex(hr, m_piRequest, __uuidof(IRequest));

                _bstr_t str1;
                hr = GetDictItemText(pDict, L"shiokaze", str1);
                if(FAILED(hr))
                        _com_issue_errorex(hr, pDict, __uuidof(IRequestDictionary));
                IXMLDOMElementPtr pElm1 = pDoc1->documentElement->firstChild;
                pElm1->text = str1;
                str1 = (BSTR)NULL;

                hr = GetDictItemText(pDict, L"chips", str1);
                if(FAILED(hr))
                        _com_issue_errorex(hr, pDict, __uuidof(IRequestDictionary));
                pElm1 = pElm1->nextSibling;
                pElm1->text = str1;
                str1 = (BSTR)NULL;

                hr = GetDictItemText(pDict, L"araiya", str1);
                if(FAILED(hr))
                        _com_issue_errorex(hr, pDict, __uuidof(IRequestDictionary));
                pElm1 = pElm1->nextSibling;
                pElm1->text = str1;
                str1 = (BSTR)NULL;

                IServerXMLHTTPRequestPtr pXMLHTTP;
                pXMLHTTP.CreateInstance(CLSID_ServerXMLHTTP);
                pXMLHTTP->open(L"POST", DataServer, VARIANT_FALSE);
                pXMLHTTP->setRequestHeader(L"Content-Type",
                        L"application/x-www-form-urlencoded");
                pXMLHTTP->send(pDoc1->xml);


                long lStatus = pXMLHTTP->status;
                if(lStatus >= 400 && lStatus <= 599)

                {
                        std::wstringstream ss;
                        ss << L"HTTP Error " << lStatus << L" : "
                                << (wchar_t *)(pXMLHTTP->statusText);
                        std::wstring s = ss.str();
                        return Error(s.c_str(), IID_IEnqSender);
                }
                m_piResponse->put_ContentType(_bstr_t(L"text/xml"));
                m_piResponse->put_CharSet(_bstr_t(L"utf-8"));
                IXMLDOMDocument2Ptr pDoc2 = pXMLHTTP->responseXML;
                pDoc2->save(_variant_t(m_piResponse));

        } catch(_com_error e) {
                return e.Error();
        }
        return S_OK;
}
HRESULT CEnqSender::GetDictItemText(IRequestDictionary *pDict, wchar_t *pwszKey, _bstr_t &strRet)
{
        _variant_t var;
        HRESULT hr = pDict->get_Item(_variant_t(pwszKey), &var);
        if(FAILED(hr))
                return hr;
        var.ChangeType(VT_BSTR);
        strRet = var.bstrVal;
        return S_OK;
}


リスト2 enq.htm(呼び出し元フォーム)
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
  <title>アンケート</title>
</head>
<body>
  <h1>アンケート</h1>
  <p>湘南を愛するみなさんにアンケートを実施しています。
  <form action="regist.asp" method="post">
    <ol>
      <li>江ノ島に行った時、潮風をテイクアウトしたいと思ったことがありますか?<br>
        <input type="radio" name="shiokaze" value="A1">ある<br>
        <input type="radio" name="shiokaze" value="A2">ない<br>
        <input type="radio" name="shiokaze" value="A3">江ノ島に行ったことがない<br>
      <li>chips に昼間行ったら何を注文しますか?<br>
        <input type="radio" name="chips" value="A1">コーヒー<br>
        <input type="radio" name="chips" value="A2">オレンジジュース<br>
        <input type="radio" name="chips" value="A3">昼には行かない<br>
        <input type="radio" name="chips" value="A4">chipsってどこ?<br>
      <li>あらいやさんのグラタンサンドは好きですか?<br>
        <input type="radio" name="araiya" value="A1">だいすっき!<br>
        <input type="radio" name="araiya" value="A2">べつに<br>
        <input type="radio" name="araiya" value="A3">たべたことない<br>
        <input type="radio" name="araiya" value="A4">あらいやさんってだれ?<br>
      </li>
    </ol>
    <input type="submit" value="送信"> <input type="reset" value="リセット">
  </form>
</body>
</html>


リスト3 regist.asp

<OBJECT ID="enqSender" RunAt="Server" CLASSID="clsid:45A87C2D-8B7F-4ADE-8B89-00774000DDC6">
</OBJECT>
<%
  enqSender.Regist "http://ai-ohta/sample05ATL/SetData.asp"
%>



(注1) エラーチェック付きバージョンを使用する場合、プロジェクトの設定で「例外処理を有効にする」をONにし、プリプロセッサの定義で「_ATL_MIN_CRT」を削除する必要があります。
(注2)http://support.microsoft.com/support/kb/articles/Q282/1/02.ASP


関連サービス

IT技術およびIT製品の可用性調査・検証業務



この記事と関連の高い記事

関連キーワード:サーバー間通信


関連キーワード:プログラミング




ページトップへ戻る