「xml」タグのついた投稿

近況報告: Psmで新作リジェクトされました! orz

 

 

・・・は置いといて、今回はxmlを読み込み、一つのクラスか構造体の配列を保存する時に使う処理を少し使い回す方法を紹介します。今回はXNAが関係無いので、C#メモ扱いにしています。

 

まずはxmlを読み込み、配列を保存するクラスの宣言をします。

 

 

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

public class XmlTable<T> where T : class, new()
{
    // XMLファイルの拡張子
    public const string _FILE_EXTENSION = ".xml";

    protected T[] m_data;

    public XmlTable()
    {
        m_data = null;
    }

 

 

Generic(T)の部分に読み込むデータの型を指定し、変数としてその型の配列を保存しています。今回はxml前提で作成していますので、拡張子名も設定しています。

 

 

それでは次は読み込む処理です。やる事はファイルを読み込み、XmlSerializerを使用して上記で指定したデータ型の配列に変換するだけです。

 

 

    public virtual void Load(string filepath, string extention = _FILE_EXTENSION)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T[]));
        System.IO.FileStream fileStream = System.IO.File.OpenRead(filepath + extention);
        m_data = (serializer.Deserialize(fileStream) as T[]);
        fileStream.Close();
    }

 

 

読み込みが終わりましたので、読み込んだデータを獲得する処理を作ります。

 

 

    public T GetData(int index)
    {
        if (m_data == null)
        {
            return null;
        }

        int length = m_data.Length;
        if (index < 0 || index >= length)
        {
            return null;
        }

        return m_data[index];
    }

 

 

後は実際に使用するだけです。やる事はデータ型の宣言、XmlTableクラスのインスタンス化、Load()処理を呼び、データを獲得します。

 

 

    public class CharaData
    {
        public int ID = -1;
        public string Name = "";
        public float MoveSpeed = 0.0f;
        public int SheetSizeX = 1;
        public int SheetSizeY = 1;
        public float AnimationTime = 0.0f;
    }

XmlTable<CharaData> m_charaTable;

        public void Load()
        {
            // インスタンス生成
            m_charaTable = new XmlTable<CharaData>();

            // 読み込み
            m_charaTable.Load( GetTablePath() );

            // データ獲得
            CharaData data = m_charaTable.GetData(0);
        }

 

 

以上です。今回は素のままの使用法を紹介しましたが、自分で使う場合はそのまま使う時と、これを継承して個別のデータ獲得方法を作ったりして使用しています。

 

 

    public class CharaDataTable
        : XmlTable<CharaData>
    {
        public CharaDataTable()
            : base()
        {
        }

        public CharaData FindData(int charaID)
        {
            int size = m_data.Length;
            for (int i = 0; i < size; ++i)
            {
                if (m_data[i].ID== charaID)
                {
                    return m_data[i];
                }
            }

            return null;
        }

 

 

今回はここまでです。一応ソース置いておきます:

そーす

C#とXnaでxmlファイルを読み込むにはSystem.xml内のクラスをを使う事もできますが、xnaにはコンテントパイプラインを使い、xmlの読み込みと書き込みをほぼ自動に行う機能が付いているので、それについてメモります。

*注意:大熊猫は英語版のVisual Studio 2010を使っているので、説明と画像には英語の部分が偶にあります。

 

コンテントパイプラインを使ってのxml操作は、IntermediateSerializerを使うと楽に出来ます。IntermediateSerializerには、xmlの書き込み時に自動的にオブジェクトの内容をコンテントパイプラインに合わせた書き方をしてくれるという利点があります。読み込み時にも、最短1行で読み込めると言う利点があります。

 

IntermediateSerializerを使うにはまず、プロジェクトにMicrosoft.Xna.Content.Pipelineを足す必要が有ります(プロジェクト内の参照を右クリックして ”Add Reference…”を選択)。もし.NETのタブ内に見つからない場合、dllを直接探して足してください(私の場合はC:\Program Files\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86 に有りました)。

Dllを足したら、プロジェクトのプロパティを開き、「アプリケーション」のタブ内で、”Target Platform”を “.Net Framework 4 Client Profile” から”.Net Framework 4”に変更してください。この設定を変更しないとIntermediateSerializerを使えないので、必ず変えてください。

プロジェクトの設定を変更し終えたら、まずxmlに保存するクラスを書きます。


class Person
{
public Vector2 Position;
public string Name;
int m_id;

public Person()
{
this.Position = Vector2.Zero;
this.Name = "";
this.m_id = -1;
}

public Person(Vector2 position, string name, int id)
{
this.Position = position;
this.Name = name;
this.m_id = id;
}

public int ID
{
get { return m_id; }
set { m_id = value; }
}

//-----ココから保存されない------//

public int GetOnlyID
{
get { return m_id; }
}

public int SetOnlyField
{
set { }
}
}

xmlに保存するクラスには幾つか注意するところがあります:

–          必ずパラメーター無しのコンストラクタが必要

–          メンバ変数は、Public設定以外は保存されない

–          アクセサはGetとSetの両方がある場合のみ、保存される

 

次は実際にxmlファイルにPersonクラスのインスタンスを保存します:


string fileName = "test.xml";
string filePath = System.IO.Directory.GetCurrentDirectory() + "\\" + fileName;
Person person = new Person(new Vector2(100.0f, 25.0f), "Ookumaneko", 100);

System.Xml.XmlWriterSettings setting = new System.Xml.XmlWriterSettings();
setting.Indent = true;

using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(fileName, setting))
{
                // xmlファイルに書き込む
IntermediateSerializer.Serialize<Person>(writer, person, filePath);
}

これでIntermediateSerializer.Serializeメソッドの第3引数で設定したパスにxmlファイルが作られます:


<?xml version="1.0" encoding="utf-8"?>
<XnaContent>
<Asset Type="XmlTest.Person">
<ID>100</ID>
<Position>100 25</Position>
<Name>Ookumaneko</Name>
</Asset>
</XnaContent>

次は書き込んだxmlファイルの読み込みです。これには二つの方法が有ります。まずはIntermediateSerializerを使用した方法です:


string fileName = "test.xml";
string filePath = System.IO.Directory.GetCurrentDirectory() + "\\" + fileName;
Person person;

System.Xml.XmlReaderSettings setting = new System.Xml.XmlReaderSettings();
using (System.Xml.XmlReader reader = System.Xml.XmlReader.Create(filePath, setting))
{
// xmlを読み込み、保存する
person = IntermediateSerializer.Deserialize<Person>(reader, null);
}

次はコンテントパイプラインを使用し、テクスチャアなどの読み込みと同じ方法です。この方法を使うには、プロジェクト上のコンテントプロジェクトにxmlファイルの追加してください。この方法を使用しての読み込みをするには、コンテントプロジェクトに読み込むクラスがあるプロジェクトに参照を通す必要が有ります。その際、プロジェクトが一つしかない場合、コンテントパイプラインとゲームプロジェクトがお互いを参照しあう事になるので、新たなプロジェクトを作る必要が有ります。(もっと楽な方法があるかただいま検索中・・・)


Person person = Content.Load<TestLib.Person>("test.xml");

テストプロジェクト:
http://www.mediafire.com/download.php?a40q8t24ae2uszj