« プロジェクトにXMLスキーマを取り込む場合の注意点 | トップページ | XMLスキーマ定義に従ってXMLファイルを読み込む(2) »

2012年10月18日 (木)

XMLスキーマ定義に従ってXMLファイルを読み込む(1)

前回、プロジェクトに取り込む場合のXMLファイル構造についての注意点を書きました。今回はその注意点に従っているという前提に基いて、XMLファイルをスキーマによる妥当性チェックを行いながら、アプリケーションで読み込むロジックについての話です。

妥当性チェックを行う場合には、XmlReaderSettings クラスを使用します。
スキーマ定義が外部のファイルを指定する場合なら、XmlDocument クラスのオブジェクトを使用して、次のような記述でいけます。


private void XMLReadTest()
{
    string xmlPath = @"C:\TestSettings.xml";     // 読み込むXMLファイルパス
    string schemaPath = @"C:\TestSettings.xsd";  // 使用するスキーマファイルパス

    XmlDocument xmlDocument = new XmlDocument();
   
    // XML読込み&妥当性検証
    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ValidationType = ValidationType.Schema;
    settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
    settings.Schemas.Add( GetXmlSchema( schemaPath ) );
    XmlReader reader = XmlReader.Create( xmlPath, settings );
    try
    {
        xmlDocument.Load( reader );
    }
    finally
    {
        reader.Close();
    }
}

private static XmlSchema GetXmlSchema( string schemaPath )
{
    XmlSchema schema = new XmlSchema();
    StreamReader reader = new StreamReader( schemaPath );
    try
    {
        schema = XmlSchema.Read( reader, null );
    }
    finally
    {
        reader.Close();
        reader.Dispose();
    }
    return schema;
}

こんな感じで記述すれば、スキーマ定義に従っていないXMLファイルを読み込むと、読み込み時点で例外が発生する筈です。

ところで、スキーマ定義をプロジェクトに取り込んだ場合、自動生成されたコードによりスキーマに従った DataSet クラスが作成されています。これを利用すれば、以下のような記述もできます。


/// <summary>
/// 指定したデータセットが持つXMLスキーマに従ってXMLファイルを読み込む。
/// スキーマに従っていない場合は例外が発生する。
/// </summary>
/// <param name="path">XMLファイルのパス</param>
/// <param name="dtSet">データセット</param>
public static void ReadXmlFile( string path, DataSet dtSet )
{
    if ( !File.Exists( path ) )
    {
        throw new FileNotFoundException( "ファイルが存在しません", path );
    }
    // XML読込み&妥当性検証
    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ValidationType = ValidationType.Schema;
    settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
    settings.Schemas.Add( GetXmlSchema( dtSet ) );
    XmlReader reader = XmlReader.Create( path, settings );
    try
    {
        // データを読み込む間、通知、インデックスの維持&制約オフ
        foreach ( DataTable dtTable in dtSet.Tables )
        {
            dtTable.BeginLoadData();
        }
        dtSet.ReadXml( reader );
        // データを読み込んだ後、通知、インデックスの維持&制約オン
        foreach ( DataTable dtTable in dtSet.Tables )
        {
            dtTable.EndLoadData();
        }
    }
    finally
    {
        reader.Close();
    }
}

/// <summary>
/// XmlSchemaクラスオブジェクトの取得
/// </summary>
/// <param name="dataSet">取得する基になるデータセット</param>
/// <returns>XmlSchemaクラスオブジェクト</returns>
private static XmlSchema GetXmlSchema(DataSet dataSet)
{
    XmlSchema schema = new XmlSchema();
    MemoryStream mem = new MemoryStream();
    try
    {
        dataSet.WriteXmlSchema( mem );
        mem.Position = 0;
        schema = XmlSchema.Read( mem, null );
    }
    finally
    {
        mem.Close();
        mem.Dispose();
    }
    return schema;
}

このやり方だと、XmlDocument クラスのオブジェクトを使いませんが、自動生成された Desiner.cs ファイルに定義された DataSet クラスのオブジェクトを利用できるので、特に問題はないと思います。というより、DataSet クラスで使用した方が、読み込んだデータの取り扱いは楽です。
それからロジック内で、読み込みの際 BeginLoadData / EndLoadData を実行しています。これは大きなサイズの XMLファイルを読み込む場合は効果が大きい様です。

なおこの部分のテストプログラムを用意したので、本記事の最後の方でダウンロード出来るようにしています。このテストプログラムを使用することを前提に、以降の話をします。なお、Visual Studio 2005までだと実行できないので、ダウンロードファイルには実行ファイルも一緒に含んでいます。

ではこのテストプログラムを実行して見ましょう。ファイルパスの指定は手抜きですので手入力しかありませんが、ここを添付のXMLファイルのパスに指定して読込ボタンをクリックすれば、きちんと読み込めているのが判ると思います。

テストプログラム実行画面

では、ここでプロジェクトに取り込んでいるスキーマ定義をちょっと変更してみましょう。ソリューションエクスプローラから、TestSettings.xsdの部分をダブルクリックすると、XMLスキーマエディタが起動します(Express Editionだと起動しません)。

ソリューションエクスプローラ操作

ここから、Left を選択して、そのプロパティを変更します。

Elementchg

これで、Left要素のデータは数値しか受け付けなくなります。添付のXMLファイルのLeft要素のデータに英字を混入させてから読み込ませると、

Validateerr

例外が発生してメッセージボックスが表示されます。同様にすれば、Top,Width,Height 等の要素も数値しか受け付けなくすることが出来ます。

この様に、XMLスキーマエディタからある程度のデータ制約条件を入れられます。入れられる制約条件は僅かですが、とにかくビジュアルで制約が入れられるというのが便利です。

今回は以上で終了します。次回、より厳しい制約条件下を入れた場合についての話をします。では、お約束のテストプグラムですが、ここからダウンロードして下さい。
「SchemaTest.zip」をダウンロード

« プロジェクトにXMLスキーマを取り込む場合の注意点 | トップページ | XMLスキーマ定義に従ってXMLファイルを読み込む(2) »

C# Tips」カテゴリの記事

コメント

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: XMLスキーマ定義に従ってXMLファイルを読み込む(1):

« プロジェクトにXMLスキーマを取り込む場合の注意点 | トップページ | XMLスキーマ定義に従ってXMLファイルを読み込む(2) »