MSXML を利用して XMLファイル を解析するには
解説
MSXML を利用して XMLファイル を解析する方法をまとめます。
便利機能
・IXMLDOM~Ptr を使う
MSXMLの処理においては、IXMLDOM~型のオブジェクトを扱います。
IXMLDOM~型には、型名の語尾にPtrが「付く」型と、「付かない」型があります。
型名の語尾にPtrが「付く」型は、スマートポインタ型なので、特に理由がない限り、型名の語尾にPtrが「付く」型を使います。
型名の語尾にPtrが「付かない」型を使う場合には、オブジェクトが不要になった際には Release関数を呼び出す、型変換は QueryInterface関数を通して行う、等が必要になります。
・CComVariant、CComBSTRを使う
MSXMLの処理においては、BSTR型やVARIANT型のオブジェクトを扱います。
BSTR型やVARIANT型には、ラッパークラスである、CComVariant型、CComBSTR型があります。特に理由がない限り、ラッパークラスである、CComVariant型、CComBSTR型を使います。
BSTR型やVARIANT型を使う場合には、領域の確保処理の記述、領域の開放処理の記述、型変換処理の記述、等が必要になります。
準備
・MSXML.DLL のインポート
#import "msxml.dll" named_guids raw_interfaces_only
をファイルヘッダー部に追加します。
これにより、MSXMLの処理が使えるようになります。
・import ディレクティブ:コンパイラは、指定されたファイルを利用可能にするヘッダーファイルを自動生成し、生成されたヘッダーを読み込みます。
・msxml.dll:msxml処理モジュールファイル。MSXML.DLLには、複数のバージョンがあります。必要に応じて、msxml.dll を msxml2.dll , msxml3.dll , msxml4.dll , msxml5.dll , msxml6.dll 等に置き換えます。
・named_guidsオプション:コンパイラは、指定されたファイルを利用可能にするヘッダーファイルに、GUID型の CLSIDやIIDの定義を生成します。
・raw_interfaces_onlyオプション:コンパイラは、指定されたファイルを利用可能にするヘッダーファイルにCOMインターフェイスの定義を生成します。
・atlbase.h のインクルード
#include
をファイルヘッダー部に追加します。
これにより、CComVariant型、CComBSTR型が使えるようになります。
・COMの初期化処理、COMの終了処理
MSXMLの処理を使うためには、COMの初期化が必要です。
CoInitialize(NULL);
をアプリケーションの開始処理部に、
CoUninitialize();
をアプリケーションの終了処理部に、
追加します。
手続き
・DOMドキュメントの作成
IXMLDOMDocumentPtr::CreateInstance 関数を利用し、IXMLDOMDocumentPtrオブジェクトを作成する。
・XMLファイル読み込み
IXMLDOMDocumentPtr::load 関数を利用して、ファイルを読み込みます。
load 関数に先立って、IXMLDOMDocumentPtr::put_async( VARIANT_FALSE ) を呼び出し、load関数が、ロードを完了するまで待つようにします。
・ノード、属性の探索、値の取得
各種 get~関数を利用して、ノード、属性を探索し、また、値の取得をします。
サンプルコード
#import "msxml6.dll" named_guids raw_interfaces_only
#include // CComVariant, CComBSTR
#include
#include
#include
bool GetXmlValue( const IXMLDOMDocumentPtr& pXMLDOMDocument,
const CComBSTR& bstrTagName,
const CComBSTR& bstrAttributeName,
std::vector& rvbstrValue )
{
// アウトプットの初期化
rvbstrValue.clear();
// インプットのチェック
if( 0 == bstrTagName.Length() )
{
return false;
}
HRESULT hResult;
// タグ名のノードリストの取得
IXMLDOMNodeListPtr pXMLDOMNodeList = NULL;
hResult = pXMLDOMDocument->getElementsByTagName( bstrTagName, &pXMLDOMNodeList );
if( FAILED(hResult) || NULL == pXMLDOMNodeList )
{
assert( !"タグ名のノードリストの取得に失敗" );
return false;
}
// ノードリストのノードの数の取得
long lCountNode = 0;
hResult = pXMLDOMNodeList->get_length( &lCountNode );
if( FAILED(hResult) )
{
assert( !"ノードリストのノードの数の取得に失敗" );
return false;
}
// ノードリストのノード一つずつ処理
for( int i = 0; i < lCountNode; ++i )
{
// ノードリストのうちの一つのノードの取得
IXMLDOMNodePtr pXMLDOMNode = NULL;
hResult = pXMLDOMNodeList->get_item( i, &pXMLDOMNode );
if( FAILED(hResult) )
{
assert( !"ノードリストのうちの一つのノードの取得に失敗" );
return false;
}
// ノードタイプの取得
DOMNodeType eNodeType;
hResult = pXMLDOMNode->get_nodeType( &eNodeType );
if( FAILED(hResult) )
{
assert( !"ノードタイプの取得に失敗" );
return false;
}
if( NODE_ELEMENT != eNodeType )
{
assert( !"ノードタイプがエレメントでないのはおかしい" );
return false;
}
// エレメント型への変換
IXMLDOMElementPtr pXMLDOMElement = NULL;
hResult = pXMLDOMNode->QueryInterface( IID_IXMLDOMElement, (void**)&pXMLDOMElement ); // スマートポインタ型を利用しているので、pXMLDOMElement = pXMLDOMNode; でも良い。
if( FAILED(hResult) || NULL == pXMLDOMElement )
{
assert( !"エレメント型への変換に失敗" );
return false;
}
// 属性値の取得か、データ値の取得か
if( bstrAttributeName.Length() )
{ // 属性値の取得
IXMLDOMAttribute* pAttributeNode = NULL;
CComVariant varValue;
hResult = pXMLDOMElement->getAttribute( bstrAttributeName, &varValue );
if( SUCCEEDED(hResult) && VT_BSTR == varValue.vt )
{
rvbstrValue.push_back( varValue.bstrVal );
}
}
else
{ // データ値の取得
CComBSTR bstrText;
hResult = pXMLDOMElement->get_text( &bstrText );
if( SUCCEEDED(hResult) )
{
rvbstrValue.push_back( bstrText );
}
}
}
return true;
}
bool ParseXmlFile( TCHAR* pszFileName )
{
if( NULL == pszFileName )
{
return false;
}
HRESULT hResult;
// DOMドキュメントの作成
IXMLDOMDocumentPtr pXMLDOMDocument;
hResult = pXMLDOMDocument.CreateInstance(CLSID_DOMDocument);
if( FAILED(hResult) )
{
assert( !"DOMドキュメントの作成に失敗" );
return false;
}
// XMLファイル読み込み
pXMLDOMDocument->put_async( VARIANT_FALSE ); // load関数がロードを完了するまで待つようにする。
VARIANT_BOOL varbResult;
hResult = pXMLDOMDocument->load( CComVariant(pszFileName), &varbResult );
if( FAILED(hResult) || !varbResult)
{
assert( !"XMLファイル読み込みに失敗" );
return false;
}
std::vector vbstrValue;
// author要素の値の取得
if( !GetXmlValue( pXMLDOMDocument,
_T("author"),
_T(""),
vbstrValue ) )
{
assert( !"author要素の値の取得に失敗" );
return false;
}
std::cout << "author要素の値" << std::endl;
for( unsigned int ui = 0; ui < vbstrValue.size(); ++ui )
{
std::cout << "\t" << _com_util::ConvertBSTRToString(vbstrValue[ui]) << std::endl;
}
// book要素のid属性の値の取得
if( !GetXmlValue( pXMLDOMDocument,
_T("book"),
_T("id"),
vbstrValue ) )
{
assert( !"book要素のid属性の値の取得に失敗" );
return false;
}
std::cout << "book要素のid属性の値" << std::endl;
for( unsigned int ui = 0; ui < vbstrValue.size(); ++ui )
{
std::cout << "\t" << _com_util::ConvertBSTRToString((TCHAR*)vbstrValue[ui]) << std::endl;
}
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL); // COMの初期化処理
ParseXmlFile( _T("books.xml") );
CoUninitialize(); // COMの終了処理
_getch();
return 0;
}
---
以下を使用していたらスマートポインタに変える
・BSTR -> CComBSTR
・SysAllocString
・SysFreeString
[変更前]
LPOLESTR s
BSTR in = SysAllocString(s);
HRESULT h = foo->bar(in);
SysFreeString(in);
[変更後]
CComBSTR in = s;
HRESULT h = foo->bar(in);
---
HRESULT h = foo->bar(CComBSTR(s));