MSXML使ってみた2
間が開きすぎて何も身についていない感のあるMSXML。
特定の属性値を持つ要素を取得して表示する処理を書いたんだけど、ずいぶん回り道をしているような感じが。もっとスッキリ書けそうな気がする。
今回も、ソースコードの利用は自己責任でお願いします。
XML
<?xml version="1.0" encoding="Shift-Jis" standalone="yes"?> <member> <person gen="1"> <name>Isono Namihei</name> <sex>Male</sex> <occupation>Office worker</occupation> </person> <person gen="1"> <name>Isono Fune</name> <sex>Female</sex> <occupation>Homemaker</occupation> </person> <person gen="2"> <name>Fuguta Sazae</name> <sex>Female</sex> <occupation>Homemaker</occupation> </person> <person gen="2"> <name>Fuguta Masuo</name> <sex>Male</sex> <occupation>Office worker</occupation> </person> <person gen="2"> <name>Isono Katsuo</name> <sex>Male</sex> <occupation>Pupil</occupation> </person> <person gen="2"> <name>Isono Wakame</name> <sex>Female</sex> <occupation>Pupil</occupation> </person> <person gen="2"> <name>Namino Norisuke</name> <sex>Male</sex> <occupation>Office worker</occupation> </person> <person gen="3"> <name>Fuguta Tarao</name> <sex>Male</sex> <occupation>Child</occupation> </person> <person gen="3"> <name>Namino Ikura</name> <sex>Male</sex> <occupation>Child</occupation> </person> </member>
ソース
BSTR型やVariant型の取り扱いには、そのラッパークラスであるCComBSTRやCComVariantを使っています。そのためにatlbase.hをインクルードしてます。atlbase.hがない場合はWindows Driver Kitに入ってるんで、そちらをインストールしてください。
#import <msxml6.dll> named_guids raw_interfaces_only #include <atlbase.h> #include <vector> #include <iostream> int ShowPersonsOfGenX(const WCHAR *pszGen); int main() { if ( FAILED(CoInitialize(NULL)) ) { return -1; } int nResult = ShowPersonsOfGenX(L"2"); CoUninitialize(); return nResult; } /* Gen="pszGen"となる人物を表示する関数 */ int ShowPersonsOfGenX(const WCHAR *pszGen) { VARIANT_BOOL fSuccess; MSXML2::IXMLDOMDocument2Ptr pDoc; HRESULT hResult = 0; pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60)); std::vector<CComBSTR> vecName; // Gen="2"となる人物の名前を格納する //XMLファイルのロード pDoc->put_async(VARIANT_FALSE); // 同期読み込みに設定 pDoc->put_validateOnParse(VARIANT_FALSE); // 妥当性確認しない hResult = pDoc->load(_variant_t("sazae.xml"), &fSuccess); if ( FAILED(hResult) || ( fSuccess != VARIANT_TRUE )) { return -1; } //personタグのノードリストを作成 MSXML2::IXMLDOMNodeListPtr pNodeListPerson = NULL; hResult = pDoc->getElementsByTagName((BSTR)L"person", &pNodeListPerson); if (FAILED(hResult) || (fSuccess != VARIANT_TRUE)) { return -1; } //ノードリストの長さを調べる long lLen = 0; hResult = pNodeListPerson->get_length(&lLen); if ( FAILED(hResult) || lLen <= 0 ) { return -1; } for (int i = 0; i < lLen; i++) { //personタグの各ノードからgen属性を探す MSXML2::IXMLDOMNodePtr pNode = NULL; hResult = pNodeListPerson->get_item(i, &pNode); if (FAILED(hResult) || (NULL == pNode)) { continue; } MSXML2::IXMLDOMElementPtr pElem = NULL; hResult = pNode->QueryInterface(IID_IXMLDOMElement, (void **)&pElem); if ( FAILED(hResult) || ( NULL == pElem ) ) { continue; } CComVariant varValue; hResult = pElem->getAttribute((BSTR)L"gen", &varValue); if ( SUCCEEDED(hResult) && ( VT_BSTR == varValue.vt ) ) { //genの属性値が"2"かどうか調べる if ( varValue == CComVariant(pszGen)) { //nameタグに書かれている名前をvecNameに入れる //personタグの子ノードをまとめたノードリストを作成する MSXML2::IXMLDOMNodeListPtr pNodeListChild = NULL; hResult = pElem->get_childNodes(&pNodeListChild); if (FAILED(hResult) || (NULL == pNodeListChild)) { continue; } //ノードリストの長さを調べる long lLenChild = 0; hResult = pNodeListChild->get_length(&lLenChild); if (FAILED(hResult) || ( lLenChild <= 0 )) { continue; } for (int j = 0; j < lLenChild; j++) { //nameタグのノードがあるかを調べる MSXML2::IXMLDOMNodePtr pNodeChild = NULL; hResult = pNodeListChild->get_item(j, &pNodeChild); if (FAILED(hResult) || (NULL == pNodeChild)) { continue; } CComBSTR bstrNode; hResult = pNodeChild->get_nodeName(&bstrNode); if (FAILED(hResult)) { continue; } if (CComBSTR(L"name") == bstrNode.m_str) { //名前を取得してvecNameに入れる CComBSTR bstrName; hResult = pNodeChild->get_text(&bstrName); if (FAILED(hResult)) { continue; } vecName.push_back(bstrName); } } } } } /* 結果を表示 */ std::vector<CComBSTR>::iterator it; std::wcout << L"Persons of Generation " << pszGen << L":" << std::endl; if ( vecName.empty() ) { std::wcout << L"There is no person who meets the condition." << std::endl; } else { for (it = vecName.begin(); it != vecName.end(); it++) { std::wcout << it->m_str << std::endl; } } return 0; }