unity xml反序列化为数据类

xml在unity中,经常用来保存本地数据,我们在处理xml文件的时候,通常是先创建一个xml对应的数据类,然后将xml解析的每一个element封装成对象,在保存的list或者diction集合中。解析xml的过程大部分都是相同的,但是不同的数据类,对应的字段,相差较大,所以之前在解析的时候,都是单独解析的。
最近闲来无事,就讲xml解析的方法进行了加工,利用c#的反射技术和泛型的特点,创建一个xml解析工具,这样,我们只用传递xml文件以及生产文件的数据类,就可以轻松搞定繁琐的xml转换了。
首先我们需要一个xml文件,手写xml文件太费劲了,我们可以先在Excel中创建数据,保存为CSV格式的文件,然后在写个工具,把csv文件转换为xml文件(虽然这样也有点麻烦,但是感觉比直接写xml要好一点)

直接上代码


using UnityEngine;
using System.Xml;
using System.IO;
using UnityEditor;
//using System;

/// <summary>
/// 把给定列数的csv文件转换为xml文件.该类文件放在file/csv文件夹下
/// csv文件的格式:第一行为属性的名称,后面若干行为属性的值
/// 生成的xml文件,放在StreamingAssets/xml目录下
/// </summary>
public class CsvToXmlTools : Editor {


    [MenuItem("Assets/CsvToXml/Story")]
    static void CsvToXml_Story(){
         string path=AssetDatabase.GetAssetPath (Selection.activeObject);
        if(path.EndsWith(".csv"))
            loadFile (path);
    }

    /// <summary>
    /// 加载csv文件,并按行读取数据.
    /// </summary>
    /// <param name="filePath">文件路径.</param>
    /// <param name="columCount">列数.</param>
    static  void loadFile(string filePath){
        string path = filePath;
        string saveName = Path.GetFileNameWithoutExtension(path);

        string xmlPath = Application.streamingAssetsPath + "/xml/" +saveName+ ".xml";
        CreatXmlFile (xmlPath);//创建或者覆盖之前的xml文件


        //读取csv文件
        FileStream fs = new FileStream (path,FileMode.Open);
        using(StreamReader sr=new StreamReader(fs)){
            string str = sr.ReadLine ();
            string[] keys = str.Split (',');//保存属性名称
//          str = sr.ReadLine ();
//          addToXml (new string[]{"dataType"},new string[]{str},xmlPath);//保存数据格式
            int columCount = keys.Length ;
            while ((str=sr.ReadLine ())!=null) {
                string[] arr = str.Split (',');
                if (keys.Length ==  arr.Length) {
                    addToXml (keys,arr,xmlPath);//保存读取的数据到xml文件中
                } else
                    Debug.LogError ("data error"+str);

            }
        }
        fs.Close ();
        Debug.Log ("转换文件结束");
    }



    /// <summary>
    /// 为xml文件添加新的节点.
    /// </summary>
    /// <param name="keys">需要添加的数据的健.</param>
    /// <param name="arr">需要添加的数据值.</param>
    /// <param name="xmlPath">xml文件的位置.</param>
    static  void addToXml(string[] keys,string[] values,string xmlPath){
        XmlDocument xmldoc = new XmlDocument ();
        xmldoc.Load (xmlPath);
        XmlNode root= xmldoc.SelectSingleNode ("root");

        XmlElement record = xmldoc.CreateElement ("Record");
        for (int i = 0; i < keys.Length; i++) {
//          Debug.Log(keys[i]+"-------"+values[i]);
            record.SetAttribute (keys [i], values [i]);
        }

        root.AppendChild (record);
        xmldoc.Save (xmlPath);

    }

    /// <summary>
    /// 创建一个新的xml文件.
    /// </summary>
    /// <param name="path">xml文件的保存路径.</param>
    static  void CreatXmlFile(string path){
        XmlDocument doc = new XmlDocument ();
        XmlDeclaration dec= doc.CreateXmlDeclaration("1.0", "utf-8", null);
        doc.AppendChild (dec);
        XmlNode root= doc.CreateElement ("root");
        doc.AppendChild (root);
        doc.Save (path);
        Debug.Log ("save path=" + path);
    }
}

这是我们的编辑器工具,选择我们的csv文件,,右键,选CsvToXml/Story,即可,生成的xml文件自动保存在StreamingAssets/xml/ 目录下,没有该目录的需要自己手动创建一下,代码里就懒得做处理了,��

然后就是我们的xml解析类,我们把xml解析放在基类里面,子类只用继承调用即可
每一个xml文件,会有一个单独的数据类和它对应,每一个字段对应一个属性

首先是我们的xml文件

<?xml version="1.0" encoding="utf-8"?>
<root>
  <Record id="1" chapter="1" index="1" content="你是故意与我争斗,以骗取启魂邪教的信任?" hero="aa" heroName="洛昭言" type="true" />
  <Record id="2" chapter="1" index="2" content="没错。不瞒兄弟,我们两人昨天刚到盈辉堡,这丫头就上了刚才那家伙的当,把钱全给了那个什么圣宗。没办法,我只好装傻跟那个教使套近乎,看能不能想法把钱弄回来" hero="bb" heroName="越今朝" type="false" />
  <Record id="3" chapter="1" index="3" content="我没上当,以前就见过穿这种衣服的骗子啊。可是你说过,要是别人都去做一件事,我最好也跟着做。昨天好多人都把钱给他了啊。" hero="aa" heroName="祈" type="true" />
  <Record id="4" chapter="1" index="4" content="我教过你明知是坑还往里跳吗?" hero="aa" heroName="越今朝" type="true" />
  <Record id="5" chapter="1" index="5" content="我教过你明知是坑还往里跳吗?" hero="bb" heroName="祈" type="false" />
  <Record id="6" chapter="2" index="1" content="我一定是上辈子欠你的…… " hero="aa" heroName="越今朝" type="true" />
  <Record id="7" chapter="2" index="2" content="加斯递交的年代" hero="bb" heroName="洛昭言" type="false" />
  <Record id="8" chapter="2" index="3" content=":那个……两位……" hero="aa" heroName="aa" type="true" />
  <Record id="9" chapter="2" index="4" content="呃……咳咳。我叫越今朝,这是越祈,兄弟怎么称呼?" hero="bb" heroName="越今朝" type="false" />
  <Record id="10" chapter="2" index="5" content="洛昭言" hero="aa" heroName="洛昭言" type="true" />
  <Record id="11" chapter="2" index="6" content="难道您就是这一带有名的昙华洛家的家主?" hero="bb" heroName="越今朝" type="false" />
</root>

然后使我们的数据基类

public class ModelBase  {

    public int id;
}

数据类

public  class StoryEntry:ModelBase{

        public string chapter;
        public string index;
        public string content;
        public string hero;
        public string heroName;
        public bool type;

//      public void show(){
//          string str = "";
//          //取得当前方法命名空间
//          str += "命名空间名:" + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace + "\n";
//          //取得当前方法类全名
//          str += "类名:" + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "\n";
//          Debug.Log (str);
//      }
    }

xml解析的基类

using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Reflection;

public class ModelMgrBase {

    public Dictionary<int,ModelBase> dataDic = new Dictionary<int, ModelBase>();

    public virtual void Init(){

    }

    /// <summary>
    /// 从 xml 中加载数据并保存到字典里面.
    /// </summary>
    /// <param name="path">Path.</param>
    /// <param name="keys">Keys.</param>
    /// <param name="className">Class name.</param>
    protected void LoadFromXml(string path,string[] keys,string className,string[] dataTypes){
        XmlDocument xml = new XmlDocument ();
        xml.Load (path);
        XmlNode root= xml.SelectSingleNode ("root");
        XmlNodeList nodes = root.ChildNodes;

//      string[] dataTypes=GetDataType ((XmlElement)nodes [0]);

        for (int i = 1; i < nodes.Count; i++) {
            XmlElement item = nodes[i] as XmlElement;

            Assembly assembly = Assembly.GetExecutingAssembly();//获取命名空间
            ModelBase model= (ModelBase)assembly.CreateInstance (className);//实例化对象
            if (model == null)
                continue;
            System.Type type= model.GetType ();

            for (int j = 0; j < keys.Length; j++) {

                FieldInfo fi= type.GetField (keys [j]);
                object dataValue=null;
                switch (dataTypes[j]) {
                case "int":
                    dataValue = int.Parse (item.GetAttribute (keys [j]));
                    break;
                case "float":
                    dataValue = float.Parse (item.GetAttribute (keys [j]));
                    break;
                case "bool":
                    dataValue = bool.Parse (item.GetAttribute (keys [j]));
                    break;
                case "string":
                    dataValue =item.GetAttribute (keys [j]);
                    break;
                default:
                    break;
                }

                if(fi!=null){

                    fi.SetValue(model,dataValue);

                }
            }

            dataDic.Add (model.id,model);

        }
    }

//  string[] GetDataType(XmlElement element){
////        Debug.Log (bool.Parse("true"));
////        Debug.Log (float.Parse("1.23"));
//      string dt = element.GetAttribute ("dataType");
//      return dt.Split(',');
//  }

    /// <summary>
    /// 通过ID从集合中查找数据.
    /// </summary>
    /// <param name="id">Identifier.</param>
    /// <typeparam name="T">The 1st type parameter.</typeparam>
    public T GetDataById<T>(int id) where T:ModelBase{
        T model;
        ModelBase mb;
        dataDic.TryGetValue (id, out mb);
        if(dataDic.ContainsKey(id)){

            return (T)dataDic[id];
        }else return default(T);
    }

    /// <summary>
    /// 通过className创建实例对象.
    /// </summary>
    /// <returns>The instance by class name.</returns>
    /// <param name="className">Class name.</param>
    /// <typeparam name="T">The 1st type parameter.</typeparam>
    private T CreateInstanceByClassName<T>(string className){
        Assembly assembly = Assembly.GetExecutingAssembly();
        object obj= assembly.CreateInstance (className);
        //      obj.GetType().GetField("chapter").SetValue(obj,21); //获取指定名称的字段
        //      System.Reflection.PropertyInfo propertyInfo = type.GetProperty("chapter"); //获取指定名称的属性
        //      propertyInfo.SetValue(obj,21,null);
        return (T)obj;
    }


}

xml数据管理类

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Reflection;


public class StoryMgr:ModelMgrBase  {

    public  class StoryEntry:ModelBase{

        public string chapter;
        public string index;
        public string content;
        public string hero;
        public string heroName;
        public bool type;

        public void show(){
            string str = "";
            //取得当前方法命名空间
            str += "命名空间名:" + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace + "\n";
            //取得当前方法类全名
            str += "类名:" + System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName + "\n";
            Debug.Log (str);
        }
    }
    private static StoryMgr instance;

    public static StoryMgr Instance{
        get
        { 
            if (instance == null)
                instance = new StoryMgr ();
            return instance;

        }
    }

 /// <summary>
 /// 初始化数据,然后假装xml,保存到字典集合中.
 /// </summary>
    public override void Init ()
    {
        base.Init ();
        string path=Application.streamingAssetsPath+"/xml/story.xml";
        string[] keys = new string[]{ "id","chapter","index","content","hero","heroName","type"};// xml 的属性名称
        string[] dataTypes = new string[]{"int","string","string","string","string","string","bool" };//对应的数据类型
        string className = "StoryMgr+StoryEntry"; //classname=命名空间+“.”+类全名,如果命名空间为空,只用添加类全名
        LoadFromXml (path,keys,className,dataTypes);
    }



}

最后,创建一个mono脚本,测试一下我们的方法

using UnityEngine;
using System.Collections;

public class testScript : MonoBehaviour {

    // Use this for initialization
    void Start () {
        StoryMgr.Instance.Init ();
        StoryMgr.StoryEntry st=StoryMgr.Instance.GetDataById<StoryMgr.StoryEntry> (3);
        Debug.Log (st.id+"--"+st.content+"--"+st.type);


    }

    // Update is called once per frame
    void Update () {

    }
}

以后再解析其他xml的时候,只要创建好数据类,然后xml管理类直接继承xml解析类,就可以将xml的数据保存到数据字典里面。

参考demo:http://download.csdn.net/detail/u011484013/9884278,unity5.4

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天涯过客TYGK

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值