ページ

2007年11月21日

XMLの読み込み

アプリの設定ファイルを XMLで書いてみたくて XMLの読み込みについて調べてみました。
ちなみに読み込みたいXMLはこんな感じです。(最初なので簡単なところから...)
<sample>
 <config name="A" type="1" />
 <config name="B" type="2" />
 <config name="C" type="3" />
</sample>

SDKのMailSetサンプルでXMLを読んでいる部分があったので参考にしてみます。
(と言うよりほとんどそのままです)

まずは サンプルで多様しているオブジェクト開放のマクロを拝借。
#define RELEASE_OBJ(s) \
 if (s != NULL) \
 { \
 s->Release(); \
 s = NULL; \
 }

続いてXMLの読み込み部分。
わかりにくくなるのでエラー処理をバッサリ切り捨てたらこんな感じになりました。
#define XML_FILE_NAME _T("\\sample.xml")
#define ROOT_ELEMENT_NAME _T("sample")
#define CONFIG_ELEMENT_NAME _T("config")
#define NAME_ATTRIBUTE_NAME _T("name")
#define TYPE_ATTRIBUTE_NAME _T("type")
// XMLファイルの読み込み
static HRESULT LoadXML()
{
 HRESULT hr = S_OK;
 IXMLDOMDocument *pDom = NULL;
 IXMLDOMNode *pTopNode = NULL,
 *pConfigNode = NULL,
 *pSibling = NULL;
 IXMLDOMNamedNodeMap *pNodeMap = NULL;
 CLSID clsid = {0};
 VARIANT vt = {0};
 VARIANT_BOOL vbSuccess = 0;
 BSTR bstrName = NULL;
 PTCHAR pszName = NULL,
 pszType = NULL;
 TCHAR szMessage[256] = _T("");
 // COMの初期化
 CoInitializeEx(NULL, 0);
 // XML DOM読み込み
 hr = CLSIDFromProgID(_T("Msxml2.DOMDocument"), &clsid);
 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (LPVOID *) &pDom);
 // XMLファイル読み込み
 vt.vt = VT_BSTR;
 vt.bstrVal = SysAllocString(XML_FILE_NAME);
 hr = pDom->load(vt, &vbSuccess);
 // ルート要素を取得
 hr = pDom->selectSingleNode(ROOT_ELEMENT_NAME, &pTopNode);
 // ルートノードの子要素の集合を取得
 hr = pTopNode->get_firstChild(&pConfigNode);
 while (pConfigNode) {
 // 子要素の名前を取得
 hr = pConfigNode->get_nodeName(&bstrName);
 if (!lstrcmpi(bstrName, CONFIG_ELEMENT_NAME)) {
 // <config>要素の場合は "name"属性と "type"属性の値を取得
 RELEASE_OBJ(pNodeMap);
 hr = pConfigNode->get_attributes(&pNodeMap);
 pszName = ReadNodeString(pNodeMap, NAME_ATTRIBUTE_NAME);
 pszType = ReadNodeString(pNodeMap, TYPE_ATTRIBUTE_NAME);
 //
 wsprintf(szMessage, _T("name=%s : type=%s"), pszName, pszType);
 MessageBox(NULL, szMessage, _T("XML読み込みテスト"), MB_OK);
 free(pszName);
 free(pszType);
 //
 }
 SysFreeString(bstrName);
 // 次の要素を選択
 hr = pConfigNode->get_nextSibling(&pSibling);
 pConfigNode->Release();
 pConfigNode = pSibling;
 }
 
 // 後始末系
 if (pszName) free(pszName);
 if (pszType) free(pszType);
 
 RELEASE_OBJ(pSibling);
 RELEASE_OBJ(pConfigNode);
 RELEASE_OBJ(pTopNode);
 RELEASE_OBJ(pNodeMap);
 RELEASE_OBJ(pDom);
 
 VariantClear(&vt);
 CoUninitialize();
 
 return hr;
}
// 指定された属性の値を読み込む
static LPTSTR ReadNodeString(IXMLDOMNamedNodeMap *pNodeMap, TCHAR *pszNodeName)
{
 HRESULT hr = S_OK;
 IXMLDOMNode *pAttlibute = NULL;
 VARIANT vt = {0};
 size_t cch = 0;
 TCHAR *pszRet = NULL;
 
 // 指定された属性の値を読み込む
 hr = pNodeMap->getNamedItem(pszNodeName, &pAttlibute);
 VariantInit(&vt);
 hr = pAttlibute->get_nodeValue(&vt);
 
 // 読み込んだ値をTCHARに変換
 // (CString使えばもっと簡単?)
 hr = StringCchLength(vt.bstrVal, STRSAFE_MAX_CCH, &cch);
 pszRet = (PTCHAR)malloc(sizeof(TCHAR) * (++cch));
 StringCchCopy(pszRet, cch, vt.bstrVal);
 
 RELEASE_OBJ(pAttlibute);
 VariantClear(&vt);
 
 return pszRet;
}

エラー処理を省いて大分見通しが良くなりましたが、それでも見慣れない型が多いですね。

とりあえず COMのの使用開始・終了に CoInitializeEx(), CoUninitialize()、 BSTRの生成・破棄に SysAllocString(), SysFreeString()、 VARIANTの初期化、クリアに VariantInit(), VariantClear()といったあたりを押さえておけばなんとかなるのでしょうか...。

0 件のコメント:

コメントを投稿

AltStyle によって変換されたページ (->オリジナル) /