プログラミング xmlのタグで検索する
あいさつ
どうも、はかせです。
インスタンシングが一段落ついたので、
今回からはxmlを使ったリソースの外部管理的なことをやってみます。
xml読み込み
xml読み込みに関しては以前の作品添削のフィードバックの際に
実装したことがあり、記事にしているのでそちらをご覧ください。
hakase0274.hatenablog.com
xmlタグ検索
xmlを使うということはデータにタグつけて、
読み込むことが目的であると思います。
ということでxmlの中から指定したタグのデータを取り出してみます。
細かい理屈の前にコードと読み込むデータです。
#pragma once #include <string> #include <winerror.h> #include <vector> #include <atlbase.h> #include <iostream> class XMLPerser { public: XMLPerser(); ~XMLPerser(); HRESULT FileLoadWithTag(std::string inPath,std::wstring inTag); };
#include "pch.h" #include "XMLPerser.h" #include<Shlwapi.h> #pragma comment(lib, "Shlwapi.lib") #import <msxml6.dll> named_guids raw_interfaces_only XMLPerser::XMLPerser() { ::CoInitialize(0); } XMLPerser::~XMLPerser() { ::CoUninitialize(); } HRESULT XMLPerser::FileLoadWithTag(std::string inPath, std::wstring inTag) { //loadの成否を格納 VARIANT_BOOL fSuccess; //XMLを読み込むDOM MSXML2::IXMLDOMDocument2Ptr pDoc; //各関数の成否を格納 HRESULT hr = 0; //DOMインスタンスを作る pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60)); //表示する要素を格納 std::vector<CComBSTR> resultVector; //XMLファイルのロード //同期読み込みに設定 pDoc->put_async(VARIANT_FALSE); //妥当性確認しない pDoc->put_validateOnParse(VARIANT_FALSE); hr = pDoc->load(_variant_t(inPath.c_str()), &fSuccess); if (FAILED(hr) || (fSuccess != VARIANT_TRUE)) return E_FAIL; //personタグのノードリストを作成 MSXML2::IXMLDOMNodeListPtr pNodeListPerson = NULL; hr = pDoc->getElementsByTagName((BSTR)L"person", &pNodeListPerson); if (FAILED(hr) || (fSuccess != VARIANT_TRUE)) return E_FAIL; //ノードリストの長さを調べる long lLen = 0; hr = pNodeListPerson->get_length(&lLen); if (FAILED(hr) || lLen <= 0) return E_FAIL; /*各personノード中から指定したTagのノードがあるか調べる*/ for (int i = 0; i < lLen; i++) { //personタグの要素を取得 MSXML2::IXMLDOMNodePtr pNode = NULL; hr = pNodeListPerson->get_item(i, &pNode); if (FAILED(hr) || (NULL == pNode)) continue; MSXML2::IXMLDOMElementPtr pElem = NULL; hr = pNode->QueryInterface(IID_IXMLDOMElement, (void **)&pElem); if (FAILED(hr) || (NULL == pElem)) continue; //personタグの子ノードをまとめたノードリストを作成する MSXML2::IXMLDOMNodeListPtr pNodeListChild = NULL; hr = pElem->get_childNodes(&pNodeListChild); if (FAILED(hr) || (NULL == pNodeListChild)) continue; //ノードリストの長さを調べる long lLenChild = 0; hr = pNodeListChild->get_length(&lLenChild); if (FAILED(hr) || (lLenChild <= 0)) continue; /*指定タグのノードがあるかを調べる*/ for (int j = 0; j < lLenChild; j++) { //子ノードの要素を取得 MSXML2::IXMLDOMNodePtr pNodeChild = NULL; hr = pNodeListChild->get_item(j, &pNodeChild); if (FAILED(hr) || (NULL == pNodeChild)) continue; //ノード名を取得 CComBSTR bstrNode; hr = pNodeChild->get_nodeName(&bstrNode); if (FAILED(hr)) continue; //取得したノードが指定したタグのノードか if (CComBSTR(inTag.c_str()) != bstrNode.m_str) continue; CComBSTR bstrName; hr = pNodeChild->get_text(&bstrName); if (FAILED(hr)) continue; resultVector.push_back(bstrName); } } /* 結果を表示 */ std::vector<CComBSTR>::iterator it; std::wcout << L"SearchTag: " << inTag << std::endl; if (resultVector.empty()) { std::wcout << L"The Tag NotFound." << std::endl; return S_FALSE; } for (it = resultVector.begin(); it != resultVector.end(); it++) { std::wcout << it->m_str << std::endl; } return S_OK; }
<?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>
コードは長いですしやたらチェックが入っていますが、
やっていることは単純です。
①XMLファイルを読み込む
②personという大きいタグ単位でデータを取得
③各person毎にノード検索を行い指定タグのノードを取得
①は以前やったやつなので割愛します。
②③は下記のコードで行います。
MSXML2::IXMLDOMNodeListPtr pNodeListPerson = NULL; hr = pDoc->getElementsByTagName((BSTR)L"タグ", &pNodeListPerson);
IXMLDOM~PtrはMSXMLでxmlデータを扱う型になります。
Ptrが付くものと付かないものがありますが、
Ptr付はスマートポインタと同種のものなので、
基本はPtr付を使えばいいと思います。
getElementsByTagNameは名前の通りタグで情報を取得する関数です。
BSTR型にワイド文字をキャストすることで使えます。
(普通のunicode文字だとうまくいきませんでした)
では実行です。
タグが存在する場合はそのタグの情報が表示され、
存在しない場合はNotFoundと出ています。