MFC
XML をファイルのように扱う(3.読込)


HomeProgramming TipsMFC Tips[MFC-018]

 ダウンロード : xml 操作サンプル(2008/07/19) ※ Unicode コンパイル環境動作確認済み。
※ このサンプルは見た目は何も変化しません。

XML 文書を読み込みます。
ここにいきなり飛んできてしまった場合は 1.準備2.保存 を先に目を通しておいてください。
こちらも保存と同様に文書ポインタをインスタンスします。


  // インスタンスの作成
  MSXML2::IXMLDOMDocumentPtr pDoc(__uuidof(MSXML2::DOMDocument40));


次に xml 文書ファイルを読み込みます。
同期指定はとりあえず読み込み完了待ちにします。
エラーが発生すると戻り値が VARIANT_TRUE 以外になります。


    // 読み込み待ちで文書を読み込む
    pDoc->put_async(VARIANT_FALSE);
    VARIANT_BOOL hr = pDoc->load(L"C:\\sample.xml");
    if (hr != VARIANT_TRUE) {
        MessageBox(_T("正常に読み込めません"), _T("構文エラー"), MB_ICONERROR);
        return;
    }


正常に読み込めたら読み込みの全ての起点となるルートエレメントを取得します。


    // ルートエレメントの取得
    MSXML2::IXMLDOMElementPtr peNow = pDoc->documentElement;


ルートが取れれば後は目的のタグを探してはノードを手繰っていきます。
タグ名からノードを取得するには getElementsByTagName() を使います。
これはリストとしてポインタを取得します。
取り出したリストに含まれるノード数は Getlength() で分かります。
Getlength() の結果が 0 なら指定のノードが見つからなかったことになります。

Getitem(連番)により一つずつ確認します。
自分の名前は peNow->nodeName で確認できます。


    MSXML2::IXMLDOMNodeListPtr plNode;
    plNode = peNow->getElementsByTagName(L"タグ名");
    int nNode = plNode->Getlength();


タグ名を自分で指定するぐらいですから、そのノードに子ノードがあるか無いかは分かっているはずです。
そのノードからテキストを取得するには以下のようにします。


    _variant_t strValue = plNode->Getitem(0)->text;
    _bstr_t wstrValue(strValue.bstrVal);


plNode に更に子ノードがぶら下がっている場合は、Getlength() の数でループさせます。

Getitem(連番)で新しいエレメントを取得します。
取得したエレメントは新しい起点として使います。


    for (int i = 0; i < plNode->Getlength(); i++) {
        MSXML2::IXMLDOMElementPtr peNow = plNode->Getitem(i);
        // ※ 以後、peNow を使用して再帰する
    }


例として保存の解説の時に作成した sample.xml を読み込んでみましょう。
まずプログラムを簡潔に記述するため以下のような関数を用意するといいでしょう。


// ---------------------------------------------------------------
// データを取り出す
// out: 取り出したテキストデータ
// ---------------------------------------------------------------
_bstr_t CFooApp::GetText(
    MSXML2::IXMLDOMElementPtr  element, // 読込元エレメント
    _bstr_t wstrTag,                    // 取得タグ名
    int     nTag                        // 何番目のデータを取得するか
)
{
    try {
        MSXML2::IXMLDOMNodeListPtr plNode;
        plNode = element->getElementsByTagName(wstrTag);
        if (plNode->Getlength() > nTag) {
            _variant_t str = plNode->Getitem(nTag)->text;
            return _bstr_t(str.bstrVal);
        }
    } catch (...) {
    }
    return L"";
}

※ 一部省略しています。

では、この GetText 関数を使って記述してみます。
下記は、あくまでも参考です。実際の記述は保存するデータ構造によって大きく異なります。


    // インスタンスの作成
    MSXML2::IXMLDOMDocumentPtr pDoc(__uuidof(MSXML2::DOMDocument40));

    // 読み込み待ちで文書を読み込む
    pDoc->put_async(VARIANT_FALSE);
    VARIANT_BOOL hr = pDoc->load(L"C:\\sample.xml");
    if (hr != VARIANT_TRUE) {
        MessageBox(_T("正常に読み込めません"), _T("構文エラー"), MB_ICONERROR);
        return;
    }

    // ルートエレメントの取得
    MSXML2::IXMLDOMElementPtr root = pDoc->documentElement;

    // ルートエレメント名を確認する
    _variant_t strRootName = root->nodeName;
    _bstr_t wstrRootName(strRootName.bstrVal);
    if (wstrRootName != _bstr_t(L"Car")) return;

    // ルートの各ノード情報を取得する
    car.wstrName  = GetText(root, L"Name");
    car.wstrMaker = GetText(root, L"Maker");

    // エンジンノードを取得する
    MSXML2::IXMLDOMNodeListPtr plNode;
    plNode = root->getElementsByTagName(L"Engine");
    if (plNode->Getlength() > 0) {  // データがあるか

        // エンジンのエレメントを取得する
        MSXML2::IXMLDOMElementPtr peEngine = plNode->Getitem(0);

        // エンジンの各ノード情報を取得する
        car.engine.wstrName = GetText(peEngine, L"Name");
        car.engine.wstrSize = GetText(peEngine, L"Size");
    }

    // タイヤノードを取得してループする
    plNode = root->getElementsByTagName(L"Tire");
    for (int nTire = 0; nTire < plNode->Getlength() && nTire < 4; nTire++) {

        // タイヤのエレメントを取得する
        MSXML2::IXMLDOMElementPtr peTire = plNode->Getitem(nTire);

        // タイヤの各ノード情報を取得する
        car.tire[nTire].wstrMaker = GetText(peTire, L"Maker");
        car.tire[nTire].wstrType  = GetText(peTire, L"Type");
    }


 << 1. 準備に戻る 
 << 2. 保存に戻る 


 Copyright 2005 VALGUS. All Rights Reserved.