DOM プログラミングレッスン
第6回:サーバー間通信を利用する(その2)
(株)日本ユニテック
太田 純
<この記事はDigital
Xpress 2001 Vol.6(12-1月号)に掲載されたものです>
前回からWebアプリケーションで他のサーバーとXMLデータを送受信する方法について扱っています。今回はデータサーバー側のコードを紹介し、このアプリケーションを完成させます。 |
XMLフォームデータをDOMに読み込む
前回の記事の中で、ServerXMLHTTPオブジェクトを使用してXML形式の情報をフォームデータとして他のサーバーに送る方法を扱いました。では、フォームデータとして送られてきたXMLデータはどのように受け取ればよいのでしょうか? データサーバー側のコードもATLを使用してプログラムしてみました。リスト1をご覧ください。このリストは、ASPからSetDataメソッドを呼ばれることを想定して書かれています。実際は処理速度が必要でなければ、ASPファイルに直接スクリプトで書くほうが簡単です。
XMLフォームデータをDOMに読み込むために必要なコードは、リスト1の(A)で示した1行のみです。DOMDocumentオブジェクトのloadメソッドに直接Requestオブジェクトを渡すだけで、フォームデータとして送られたXMLデータをDOMとして取得できます。前回の記事の中で通常のHTMLフォームデータからデータを取り出す場合のコード例を示しましたが、比べればこの簡単さは一目瞭然です。
XMLとデータベースを連携させる
リスト1の(B)で示した行から始まるforループにおいて、DOMのプロパティーを使用して取り出したテキストをデータベースに書き込むコードを示しました。データベースのインターフェイスにはADOを使用しています。このコードは通常のDOMプログラミングそのままのコードで、特に変わったところはありません。データベース上のテーブルの形式は表1のようになっています。id列が質問番号で、他の各行には回答数が入ります。リスト1の処理は、テーブルから該当するセルのデータを取り出して、1加えて書き戻すだけの簡単な処理です。
id
|
A1
|
A2
|
A3
|
A4
|
A5
|
1
|
0
|
6
|
2
|
0
|
0
|
2
|
1
|
4
|
2
|
1
|
0
|
3
|
0
|
3
|
4
|
1
|
0
|
表1 本サンプルで使用したテーブルの形式
次に、現在の集計結果をデータベースからXML形式で取り出します。リスト1の(C)で、ADOのRecordsetオブジェクトをDOMオブジェクトに保存するやり方を示します。RecordsetオブジェクトのSaveメソッドで、第1引数にDOMDocumentを、第2引数にadPersistXMLを指定すると、DOMDocumentにデータベースの内容が入ります。#importで自動生成したクラスから_variant_tへの変換は、暗黙の変換では期待する結果を得られません。第1引数をいったんLPDISPATCHにキャストする必要があることに注意してください。この時、第1引数にファイル名を指定すればそのファイルにXMLデータを保存できます。ここで受け取れるXMLデータをリスト2に示しました。
リスト2のXMLデータを見ていただくと、最上位要素にxmlという名前が付けられています。xml要素はInternet
Explorer 5.0以降で使われるHTMLの要素名です。つまり、本来のXMLの仕様としては要素名に「xml」を使ってはいけないはずなのですが、MicrosoftはこのXMLデータをHTMLに埋め込むことを考えてこのような要素名を付けたようです。
xml要素の子要素には、スキーマを示すs:Schema要素とデータを表すrs:data要素があります。このサンプルではこのXML形式のままResponseに書き込むことにしました。
前回のサンプルコードと組み合わせると、リスト2と同様の内容を持つXMLデータがブラウザ上に表示されます。実際のアプリケーションでは、rs:dataの下にある情報(リスト2で強調した部分)をXSLTで整形して表示させるとよいでしょう。
まとめ
6回にわたってお送りした「DOMプログラミングレッスン」は今回でいったん終了とさせていただきます。この連載では、ちまたによくあるDOM解説記事でわかる範囲のことは扱わない方針で書いてきましたから、わかりにくく思えた方も多くいらっしゃったことと思います。MSXMLのオンラインヘルプも活用しながらサンプルコードを見直していただきたいと思います。また、この連載ではC++中心の解説を行いましたが、システム構成に合った適切な言語の選択も必要です。スクリプト言語で動作確認した後、処理速度などの必要に応じてC++も併用していくことをお勧めしたいと思います。
リスト1 SeverXMLHTTPを使用する
STDMETHODIMP CEnqRegister::SetData()
{
IXMLDOMDocument2Ptr pDoc1;
HRESULT hr = pDoc1.CreateInstance(CLSID_DOMDocument);
if(FAILED(hr))
return hr;
try {
pDoc1->async = VARIANT_FALSE;
pDoc1->load(_variant_t(m_piRequest));
// (A)
_ConnectionPtr pCon;
hr = pCon.CreateInstance(__uuidof(Connection));
if(FAILED(hr))
_com_raise_error(hr);
pCon->Open(
_bstr_t(L"Provider=SQLOLEDB;Server=(local);Uid=sa;Pwd=;Database=ShonanEnq"),
_bstr_t(L""), _bstr_t(L""), adConnectUnspecified);
_RecordsetPtr pRs;
hr = pRs.CreateInstance(__uuidof(Recordset));
pRs->Open(_variant_t(L"Enq"), _variant_t((LPDISPATCH)pCon),
adOpenDynamic,
adLockPessimistic, adOptionUnspecified);
pRs->MoveFirst();
pCon->BeginTrans();
IXMLDOMNodePtr pE;
IXMLDOMNodeListPtr pList = pDoc1->documentElement->childNodes;
for(int i = 0; i < pList->Getlength(); i++) //(B)
{
pE = pList->Getitem(i);
_bstr_t strField = pE->text;
FieldPtr pF = pRs->Fields->GetItem(strField);
pF->Value = _variant_t(pF->Value.lVal + 1L);
pRs->MoveNext();
}
pCon->CommitTrans();
pRs->Close();
IXMLDOMDocument2Ptr pDoc2;
HRESULT hr = pDoc2.CreateInstance(CLSID_DOMDocument);
if(FAILED(hr))
_com_raise_error(hr);
pRs->Open(_variant_t(L"Enq"), _variant_t((LPDISPATCH)pCon), adOpenDynamic, adLockPessimistic, adOptionUnspecified);
pRs->Save(_variant_t((LPDISPATCH)pDoc2), adPersistXML); //(C)
pRs->Close();
pRs = NULL;
pCon->Close();
pCon = NULL;
m_piResponse->put_ContentType(_bstr_t(L"text/xml"));
m_piResponse->Write(_variant_t(pDoc2->xml));
} catch(_com_error e) {
return e.Error();
}
return S_OK;
}
|
リスト2 ADO RecordsetのSaveメソッドで保存されるXMLデータ
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType name="row" content="eltOnly"
rs:CommandTimeout="30" rs:updatable="true">
<s:AttributeType name="id" rs:number="1"
rs:writeunknown="true" rs:basecatalog="ShonanEnq"
rs:basetable="Enq" rs:basecolumn="id"
rs:keycolumn="true">
<s:datatype dt:type="int" dt:maxLength="4"
rs:precision="10" rs:fixedlength="true"
rs:maybenull="false"/>
</s:AttributeType>
<s:AttributeType name="A1" rs:number="2"
rs:nullable="true" rs:writeunknown="true"
rs:basecatalog="ShonanEnq" rs:basetable="Enq"
rs:basecolumn="A1">
<s:datatype dt:type="int" dt:maxLength="4"
rs:precision="10" rs:fixedlength="true"/>
</s:AttributeType>
<s:AttributeType name="A2" rs:number="3"
rs:nullable="true" rs:writeunknown="true"
rs:basecatalog="ShonanEnq" rs:basetable="Enq"
rs:basecolumn="A2">
<s:datatype dt:type="int" dt:maxLength="4"
rs:precision="10" rs:fixedlength="true"/>
</s:AttributeType>
<s:AttributeType name="A3" rs:number="4"
rs:nullable="true" rs:writeunknown="true"
rs:basecatalog="ShonanEnq" rs:basetable="Enq"
rs:basecolumn="A3">
<s:datatype dt:type="int" dt:maxLength="4"
rs:precision="10" rs:fixedlength="true"/>
</s:AttributeType>
<s:AttributeType name="A4" rs:number="5"
rs:nullable="true" rs:writeunknown="true"
rs:basecatalog="ShonanEnq" rs:basetable="Enq"
rs:basecolumn="A4">
<s:datatype dt:type="int" dt:maxLength="4"
rs:precision="10" rs:fixedlength="true"/>
</s:AttributeType>
<s:AttributeType name="A5" rs:number="6"
rs:nullable="true" rs:writeunknown="true"
rs:basecatalog="ShonanEnq" rs:basetable="Enq"
rs:basecolumn="A5">
<s:datatype dt:type="int" dt:maxLength="4"
rs:precision="10" rs:fixedlength="true"/>
</s:AttributeType>
<s:extends type="rs:rowbase"/>
</s:ElementType>
</s:Schema>
<rs:data>
<z:row
id="1" A1="0" A2="6" A3="2"
A4="0" A5="0"/>
<z:row
id="2" A1="1" A2="4" A3="2"
A4="1" A5="0"/>
<z:row
id="3" A1="0" A2="3" A3="4"
A4="1" A5="0"/>
</rs:data>
</xml> |
関連サービス
IT技術およびIT製品の可用性調査・検証業務
関連キーワード: サーバー間通信
関連キーワード: プログラミング
|