ストリーム

ストリームから読み込む

このエントリーをはてなブックマークに追加
最終更新日 2016-12-31

XmlLite は、XML を読み込むためにストリームを使用します。以下に示すのは、ファイルのストリームから XML を読み込む例と、 メモリのストリームから XML を読み込む例です。

ファイルストリーム

次に示すのは、XML ファイルのストリームから XML を読み込む例です。 あらかじめ sample.xml というファイルをプログラムと同じフォルダに用意しておき、 XML を読み込んだ結果をメッセージボックスに表示します。 なお、sample.xml のエンコードは XmlLite がネイティブでサポートする UTF-8 とします。

プロジェクトファイル ダウンロード

// sample.xml
<?xml version="1.0" encoding="UTF-8"?>
<sample>
  <requirement>
    <type>ヘッダ</type>
    <name>XmlLite.h</name>
  </requirement>
  <requirement>
    <type>ライブラリ</type>
    <name>XmlLite.lib</name>
  </requirement>
</sample>
// stdafx.h
#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS

#include <atlbase.h>  // CComPtrを使用するため
#include <atlstr.h>   // CStringを使用するため

#include <xmllite.h>
#pragma comment(lib, "xmllite.lib")
// SampleProject.cpp
#include "stdafx.h"

void Run()
{
    CComPtr<IXmlReader> pReader;
    if(FAILED(CreateXmlReader(__uuidof(IXmlReader), reinterpret_cast<void**>(&pReader), 0))){
        MessageBox(NULL, _T("CreateXmlReader失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
        return;
    }

    // XMLファイルパス作成
    TCHAR xml[MAX_PATH];
    GetModuleFileName(NULL, xml, sizeof(xml) / sizeof(TCHAR));
    PathRemoveFileSpec(xml);
    PathAppend(xml, _T("sample.xml"));

    // ファイルストリーム作成
    CComPtr<IStream> pStream;
    if(FAILED(SHCreateStreamOnFile(xml, STGM_READ, &pStream))){
        MessageBox(NULL, _T("SHCreateStreamOnFile失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
        return;
    }

    if(FAILED(pReader->SetInput(pStream))){
        MessageBox(NULL, _T("SetInput失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
        return;
    }

    CString result;
    LPCWSTR pwszLocalName;
    LPCWSTR pwszValue;
    XmlNodeType nodeType;
    while(S_OK == pReader->Read(&nodeType)){
        switch(nodeType){
        case XmlNodeType_Element:
            if(FAILED(pReader->GetLocalName(&pwszLocalName, NULL))){
                MessageBox(NULL, _T("GetLocalName失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
                return;
            }
            break;
        case XmlNodeType_Text:
            if(FAILED(pReader->GetValue(&pwszValue, NULL))){
                MessageBox(NULL, _T("GetValue失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
                return;
            }
            CString row;
            if(lstrcmp(pwszLocalName, _T("type")) == 0){
                row.Format(_T("種類:%s\n"), pwszValue);
            }else if(lstrcmp(pwszLocalName, _T("name")) == 0){
                row.Format(_T("名前:%s\n\n"), pwszValue);
            }
            result += row;
            break;
        }
    }

    MessageBox(NULL, result, _T("結果"), MB_OK | MB_ICONINFORMATION);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    Run();

    return 0;
}

まず、stdafx.h ヘッダでは、ATL の CComPtr と CString を使用するために atlbase.h ヘッダと atlstr.h ヘッダをインクルードします。 また、XmlLite を使用するために xmllite.h ヘッダをインクルードし、#pragma ディレクティブで xmllite.lib をリンクします。

_tWinMain() から呼び出される Run() では、まず、CreateXmlReader() を呼び出して IXmlReader インターフェイスの実装を取得します。 CreateXmlReader() の第1引数はインターフェイスID、第2引数は IXmlReader のスマートポインタへのポインタ、 第3引数はユーザがメモリ割り当てを制御するための IMalloc 実装へのポインタです。

次に、SHCreateStreamOnFile() を呼び出して読み込み用のファイルストリームを作成し、 IXmlReader::SetInput() を呼び出してファイルストリームを関連付けます。

次に、IXmlReader::Read() を呼び出して、読み込んだ XML のノードタイプを解析します。ノードタイプには次の種類が用意されています。

ノードタイプ 説明
XmlNodeType_None なし
XmlNodeType_Element 要素の開始
XmlNodeType_Attribute 属性
XmlNodeType_Text テキスト
XmlNodeType_CDATA CDATAセクション
XmlNodeType_ProcessingInstruction XMLプロセッサ処理命令
XmlNodeType_Comment コメント
XmlNodeType_DocumentType ドキュメントの型宣言(DTD)
XmlNodeType_Whitespace 空白
XmlNodeType_EndElement 要素の終了
XmlNodeType_XmlDeclaration XML宣言

今回の例では、ノードタイプが XmlNodeType_Element の場合に IXmlReader::GetLocalName() を呼び出して要素名を取得し、 ノードタイプが XmlNodeType_Text の場合に IXmlReader::GetValue() を呼び出してテキストを取得します。

メモリストリーム

次に示すのは、先述のプログラムを変更してメモリのストリームから XML を読み込む例です。 文字列としての XML を読み込んだ結果をメッセージボックスに表示します。

プロジェクトファイル ダウンロード

// stdafx.h
#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS

#include <atlbase.h>  // CComPtrを使用するため
#include <atlstr.h>   // CStringを使用するため

#include <xmllite.h>
#pragma comment(lib, "xmllite.lib")
// SampleProject.cpp
#include "stdafx.h"

void Run()
{
    CComPtr<IXmlReader> pReader;
    if(FAILED(CreateXmlReader(__uuidof(IXmlReader), reinterpret_cast<void**>(&pReader), 0))){
        MessageBox(NULL, _T("CreateXmlReader失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
        return;
    }

    // 文字列としてのXML
    LPCWSTR xml = 
        L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
        L"<sample>"
          L"<requirement>"
            L"<type>ヘッダ</type>"
            L"<name>XmlLite.h</name>"
          L"</requirement>"
          L"<requirement>"
            L"<type>ライブラリ</type>"
            L"<name>XmlLite.lib</name>"
          L"</requirement>"
        L"</sample>";

    // XML用メモリ割り当て
    HGLOBAL hXml = GlobalAlloc(GMEM_MOVEABLE, (lstrlen(xml) + 1) * sizeof(WCHAR));
    LPWSTR buf = reinterpret_cast<LPWSTR>(GlobalLock(hXml));
    lstrcpy(buf, xml);
    GlobalUnlock(hXml);

    // メモリストリーム作成
    CComPtr<IStream> pStream;
    if(FAILED(CreateStreamOnHGlobal(hXml, TRUE, &pStream))){
        MessageBox(NULL, _T("CreateStreamOnHGlobal失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
        return;
    }

    if(FAILED(pReader->SetInput(pStream))){
        MessageBox(NULL, _T("SetInput失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
        return;
    }

    CString result;
    LPCWSTR pwszLocalName;
    LPCWSTR pwszValue;
    XmlNodeType nodeType;
    while(S_OK == pReader->Read(&nodeType)){
        switch(nodeType){
        case XmlNodeType_Element:
            if(FAILED(pReader->GetLocalName(&pwszLocalName, NULL))){
                MessageBox(NULL, _T("GetLocalName失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
                return;
            }
            break;
        case XmlNodeType_Text:
            if(FAILED(pReader->GetValue(&pwszValue, NULL))){
                MessageBox(NULL, _T("GetValue失敗"), _T("警告"), MB_OK | MB_ICONWARNING);
                return;
            }
            CString row;
            if(lstrcmp(pwszLocalName, _T("type")) == 0){
                row.Format(_T("種類:%s\n"), pwszValue);
            }else if(lstrcmp(pwszLocalName, _T("name")) == 0){
                row.Format(_T("名前:%s\n\n"), pwszValue);
            }
            result += row;
            break;
        }
    }

    MessageBox(NULL, result, _T("結果"), MB_OK | MB_ICONINFORMATION);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    Run();

    return 0;
}

変更するのは、ストリームを作成する部分です。まず、文字列としての XML を用意します。 この際、XML のエンコードは UTF-16 とします。これは、プロジェクトを Unicode ビルドすると、文字列の文字コードが UTF-16 になるためです。 XmlLite は UTF-16 をネイティブでサポートします。次に、GlobalAlloc()、GlobalLock()、GlobalUnlock() を呼び出して XML 文字列を保持するメモリを割り当て、 CreateStreamOnHGlobal() を呼び出してメモリストリームを作成します。 CreateStreamOnHGlobal() の第2引数には TRUE を指定しているため、ストリームが解放されるタイミングで、 割り当てたメモリも自動的に解放されます。