MFC
XML をファイルのように扱う(2.保存)


HomeProgramming TipsMFC Tips[MFC-017]

XML を扱うための準備は出来ましたか?
まだの場合は前のページに戻って確認をしてください。

このページではデータをファイルに保存する方法を解説します。


■ データを XML 保存する。

最初に xml 文書をインスタンスします。
まあ、入れ物を作るようなモノだと思ってください。


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


これで空の文書が出来ました。
次に全ての起点となるルートノードを作成します。
文字エンコードはここではシフトJISを使用することにします。
ルートを作成する方法は2通りあるようです。
ここではルートノードを一気に作成する loadXML() を使います。
下記のサンプルはルートとして <Root> を作成しています。


  // ルートノードの作成
  pDoc->loadXML(L"<?xml version=\"1.0\" encoding=\"Shift_JIS\" ?>\n<Root/>");
  MSXML2::IXMLDOMElementPtr root = pDoc->documentElement;


これでルートが出来ました。このルートに次々とデータを追加していきます。
追加するデータは Unicode テキストのみです。
数値を保存したければ文字列化します。
文字列は _bstr_t を使って表します。

保存は子ノードを追加した後でテキストデータを書き込みという手順を踏みます。
以下のような関数を作っておくと便利でしょう。


// ---------------------------------------------------------------
// ノードを追加する
// out: 追加したノードポインタ
// ---------------------------------------------------------------
MSXML2::IXMLDOMElementPtr CFooApp::AddNode(
    MSXML2::IXMLDOMDocumentPtr pDoc,    // 追加する文書
    MSXML2::IXMLDOMElementPtr  root,    // 追加元ノード
    _bstr_t wstrNode,                   // 追加ノード名
    _bstr_t wstrText                    // 追加テキストデータ
)
{
    // ルートに子ノードを追加する
    MSXML2::IXMLDOMElementPtr peNew = pDoc->createElement(wstrNode);
    root->appendChild(peNew);

    // リーフテキストデータを書き込む
    peNew->appendChild(pDoc->createTextNode(wstrText));

    return peNew;
}



この関数を使えば、どのノードにどんな情報をぶら下げるか指定することが出来ます。
例えば、root に「AppName」というノードを「サンプルデータ」というデータを追加する場合は、
下記のような使い方をすれば OK です。


    AddNode(pDoc, root, L"AppName", L"サンプルデータ");


作成した子ノードの下に更にノードをぶら下げるには、AddNode の返り値を次のルートとして使用します。
例えばルート→1→2→3と次々ぶら下げていくには下記のようになります。


    MSXML2::IXMLDOMElementPtr lv1, lv2, lv3;
    lv1 = AddNode(pDoc, root, L"AppName", L"サンプルデータ");
    lv2 = AddNode(pDoc, lv1,  L"Level1",  L"第一階層データ");
    lv3 = AddNode(pDoc, lv2,  L"Level2",  L"第二階層データ");


より具体的に示しましょう。
階層構造を持つ構造体を xml 文書として保存します。
保存する構造体とその変数を以下の通りとします。


struct TEngine {
    _bstr_t wstrName;   // 型式
    _bstr_t wstrSize;   // 排気量
};

struct TTire {
    _bstr_t wstrMaker;  // メーカー名
    _bstr_t wstrType;   // タイプ
};

struct TCar {
    _bstr_t wstrName;   // 車名
    _bstr_t wstrMaker;  // メーカー名
    TEngine engine;     // エンジン
    TTire   tire[4];    // タイヤ
};

TCar car;


この構造体変数 car の各メンバを、階層構造を保持したまま xml 文書として保存するには下記のようになります。


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

    // ルートノードの作成
    pDoc->loadXML(L"<?xml version=\"1.0\" encoding=\"Shift_JIS\" ?>\n<Car/>");
    MSXML2::IXMLDOMElementPtr root = pDoc->documentElement;
    MSXML2::IXMLDOMElementPtr engine, tire;

    // ノードを追加する
    AddNode(pDoc, root, L"Name",  car.wstrName);
    AddNode(pDoc, root, L"Maker", car.wstrMaker);

    // ルートにエンジンノードを追加する
    engine = AddNode(pDoc, root, L"Engine", L"")
    AddNode(pDoc, engine, L"Name",  car.engine.wstrName);
    AddNode(pDoc, engine, L"Size",  car.engine.wstrSize);

    // ルートにタイヤノードを追加する
    for (int i = 0; i < 4; i++) {
        tire = AddNode(pDoc, root, L"Tire", L"");
        AddNode(pDoc, tire, L"Maker", car.tire[i].wstrMaker);
        AddNode(pDoc, tire, L"Type",  car.tire[i].wstrType);
    }


これで pDoc には目的の xml 文書が完成しています。
後はファイルとして吐き出すだけです。
これも簡単で save メソッドを使って保存するだけです。


    // XML文書を保存する
    pDoc->save(L"C:\\sample.xml");


なお、改行を出力していませんので吐き出された xml ファイルはヘッダ以外は一行になっています。
インデント付き改行出力を行いたい場合は、>> MFC-027 MSXML の出力をインデントする を参照してください。

以上で保存が出来ました。
次はデータの読込を解説します。

 << 1. 準備に戻る 
 >> 3. 読込に進む 


 Copyright 2005 VALGUS. All Rights Reserved.