unity进阶学习笔记:json和xml

1早期的数据格式

在早期程序开发中一个简单且常用的数据格式为CSV。该格式单纯依靠逗号来分割数据。目前windows的office依然支持CSV解析,我们可以试着新建一个txt文件,在里面加入逗号分隔的信息:

a, 1, 15, 30, true

将txt文件后缀改为csv,可以看到系统自动生成了一个excel表格,由空格分隔的每一项都成了表格的一个单元。但显然这种方法可读性很差,因此对于存储大量数据不常用

2 json

json是一种“数组+对象” 的数据存储方式,其中[ ]内为数组,{ }内为对象,例如

{
    
    
	"Persons":[
		{
    
    
			"name":"a",
			"age":18
		},
		{
    
    
			"name":"b",
			"age":17
		}
	]
}

unity自带json数据创建和解析的功能JsonUtility。

示例:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[Serializable]
public class Person {
    
    
    public string name;
    public int age;
}


[Serializable]
public class Persons {
    
    
    public Person[] persons;
}


public class JsonUtilityTest : MonoBehaviour
{
    
    
    // Start is called before the first frame update
    void Start()
    {
    
    
        Person person = new Person();
        person.name = "a";
        person.age = 18;
        Person person2 = new Person();
        person2.name = "b";
        person2.age = 17;
        Persons persons = new Persons();
        persons.persons = new Person[] {
    
    person, person2};
        string jsonStr = JsonUtility.ToJson(persons);
        Debug.Log(jsonStr);

        Persons ps = JsonUtility.FromJson<Persons>(jsonStr);
        foreach (Person p in ps.persons) {
    
    
            Debug.Log(p.name);
        }
    }


}

1

using System;

要使用JsonUtility工具,要先在文件中引入System

2

[Serializable]
public class Person {
    
    
    public string name;
    public int age;
}


[Serializable]
public class Persons {
    
    
    public Person[] persons;
}

这里我们创建两个类Person和Persons用于示例。在类前面的标记[Serializable]代表可序列化,只有带有该标记的类才能转化为json格式

3

string jsonStr = JsonUtility.ToJson(persons);

在我们创建并赋值Persons对象后,使用JsonUtility.ToJson()方法即可将对象自动转化为json文件,其内容如下:
{“persons”:[{“name”:“a”,“age”:18},{“name”:“b”,“age”:17}]}

Persons ps = JsonUtility.FromJson<Persons>(jsonStr);

要解析json文件,我们使用方法JsonUtility.FromJson<类型>()得到json文件最外层的数据类型,然后即可对该数据进行层层拆包得到里面的数据

除了系统自带的JsonUtility方法,还有很多常用的第三方json数据处理方法,如LitJson

下载LitJson的dll文件后,在unity Assets文件夹下面创建Plugins文件夹,并把LitJson.dll放入该文件夹。在C#脚本中引入LitJson即可使用LitJson文件

LitJson使用示例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LitJson;


public class Heros {
    
    
    public Hero[] heros;
}

public class Hero {
    
    
    public string name;
    public int age;
}

public class TestLitJson : MonoBehaviour
{
    
    
    // Start is called before the first frame update
    void Start()
    {
    
    
        fun3();
    }


    void fun1() {
    
    
        Hero hero1 = new Hero();
        hero1.name = "Superman";
        hero1.age = 35;
        Hero hero2 = new Hero();
        hero2.name = "Batman";
        hero2.age = 38;

        Heros heros = new Heros();
        heros.heros = new Hero[] {
    
    hero1, hero2};
        string jsonStr = JsonMapper.ToJson(heros);
        Debug.Log(jsonStr);

        Heros hs = JsonMapper.ToObject<Heros>(jsonStr);
        Debug.Log(hs.heros[1].name);
    }

    // using JsonData type
    void fun2() {
    
    
        JsonData jd1 = new JsonData();
        jd1.SetJsonType(JsonType.Object);
        jd1["name"] = "Superman";
        jd1["age"] = 35;
        JsonData jd2 = new JsonData();
        jd2.SetJsonType(JsonType.Object);
        jd2["name"] = "Batman";
        jd2["age"] = 38;
        JsonData jds = new JsonData();
        jds.SetJsonType(JsonType.Array);
        jds.Add(jd1);
        jds.Add(jd2);
        JsonData heroJd = new JsonData();
        heroJd.SetJsonType(JsonType.Object);
        heroJd["heros"] = jds;
        Debug.Log(heroJd.ToJson());
    }


    void fun3() {
    
    
        string jsonStr = "{'heros':[{'name':'Superman','age':35},{'name':'Batman','age':38}]}";
        JsonData herosJd = JsonMapper.ToObject(jsonStr);
        JsonData heros = herosJd["heros"];
        foreach (JsonData heroJd in heros) {
    
    
            Debug.Log(heroJd["name"].ToString() + " " + (int)heroJd["age"]);
        }
    }
}

1

    void fun1() {
    
    
        Hero hero1 = new Hero();
        hero1.name = "Superman";
        hero1.age = 35;
        Hero hero2 = new Hero();
        hero2.name = "Batman";
        hero2.age = 38;

        Heros heros = new Heros();
        heros.heros = new Hero[] {
    
    hero1, hero2};
        string jsonStr = JsonMapper.ToJson(heros);
        Debug.Log(jsonStr);

        Heros hs = JsonMapper.ToObject<Heros>(jsonStr);
        Debug.Log(hs.heros[1].name);
    }

和JsonUtility类似,LitJson可以根据一个类创建json文件,使用JsonMapper.ToJson文件

要解析Json文件,使用JsonMapper.ToObject方法,可得到Json文件解析后的对象

2

    // using JsonData type
    void fun2() {
    
    
        JsonData jd1 = new JsonData();
        jd1.SetJsonType(JsonType.Object);
        jd1["name"] = "Superman";
        jd1["age"] = 35;
        JsonData jd2 = new JsonData();
        jd2.SetJsonType(JsonType.Object);
        jd2["name"] = "Batman";
        jd2["age"] = 38;
        JsonData jds = new JsonData();
        jds.SetJsonType(JsonType.Array);
        jds.Add(jd1);
        jds.Add(jd2);
        JsonData heroJd = new JsonData();
        heroJd.SetJsonType(JsonType.Object);
        heroJd["heros"] = jds;
        Debug.Log(heroJd.ToJson());
    }

除了利用对象创建Json文件,LitJson还支持不创建对象,直接使用JsonData创建Json文件。JsonData类型包括了Int Double Boolean Array Object等常用类型。

在上面代码中,我们创建JsonData类jd1,之后使用SetJsonType将其类型设为Object(这一句可以省略,LitJson会自动判断数据类型)。

对于Object类,使用键值对来添加值,对于数组,使用Add方法添加元素

void fun3() {
    
    
        string jsonStr = "{'heros':[{'name':'Superman','age':35},{'name':'Batman','age':38}]}";
        JsonData herosJd = JsonMapper.ToObject(jsonStr);
        JsonData heros = herosJd["heros"];
        foreach (JsonData heroJd in heros) {
    
    
            Debug.Log(heroJd["name"].ToString() + " " + (int)heroJd["age"]);
        }
    }

JsonMapper.ToObject方法除了支持使用泛型将Json数据解析成特定类型,还可以不使用泛型,解析完的数据默认类型全部为JsonData类型,包括内部的所有类的数据。因此在Debug.Log中我们要先将name和age分别转换为String和int类型

2 xml

xml是一种常用的标记语言,语法和html很类似,都由节点组成。我们以下面例子来讲解

<?xml version="1.0" encoding="utf-8"?>
<root>
    <heros>
        <hero id="1">
            <name>Superman</name>
            <age>35</age>
        </hero>
        <hero id="2">
            <name>Batman</name>
            <age>37</age>
        </hero>
        <hero id="3">
            <name>Spiderman</name>
            <age>30</age>
        </hero>
    </heros>
</root>

1

<?xml version="1.0" encoding="utf-8"?>

这一句用于声明xml格式,标明版本和使用编码

2

 <root></root>

为根节点,根节点只能有一个。其他所有节点在根节点内部。

3 <hero id="1"> <name>Superman</name> <age>35</age> </hero>

对于一个节点,里面要么保存字符串值,要么保存一个子节点(不可同时保存)。节点尖括号内部可以添加属性(即为节点变量),属性值必须包括在""里面

解析xml文件(方法1)

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

public class XMLTest : MonoBehaviour
{
    
    
    // Start is called before the first frame update
    void Start()
    {
    
    
        parseXml();
    }

    
    void parseXml() {
    
    
        // xml文档类
        XmlDocument doc = new XmlDocument();
        doc.Load(Application.dataPath + "/XML/testXml.xml");
        // root
        XmlElement rootEle = doc.LastChild as XmlElement;   
        // heros
        XmlElement herosEle = rootEle.FirstChild as XmlElement;
        // heor
        foreach(XmlElement heroEle in herosEle.ChildNodes) {
    
    
            string id = heroEle.GetAttribute("id");
            string name = heroEle.ChildNodes[0].InnerText;
            string age = heroEle.ChildNodes[1].InnerText;
            Debug.Log(id + name + age);
        }
    }
}

在文件开头要引入System.Xml以使用xml工具

xml文件类型称为XmlDocument。我们先创建新的XmlDocument对象并导入刚才创建的xml文件

LastChild FirstChild方法用于获取节点的第一个和最后一个元素。ChildNodes数组保存节点里面所有元素。获取到的元素类型XmlNode,该类型为XmlElement的子类,因此获取到XmlElement需要进行类型转换

GetAttribute方法用于获取节点内的属性。要得到节点内保存的值使用方法InnerText

解析xml文件(方法2)

    void parseXml2() {
    
    
        XmlDocument doc = new XmlDocument();
        doc.Load(Application.dataPath + "/XML/testXml.xml");
        XmlNodeList list = doc.SelectNodes("/root/heros/hero/name");
        foreach (XmlElement element in list) {
    
    
            Debug.Log(element.InnerText);
        }
    }

除了常规从根目录进行解析,我们可以实现XPath直接通过文件路径访问到特定的节点。在上面例子中,SelectNodes()根据给出的XPath路径找到所有符合该路径的节点,得到结果Superman,Batman,Spiderman

XPath路径还有几种特殊写法
1 相对路径

XmlNodeList list = doc.SelectNodes(“//name”);

//代表使用相对路径。此时我们会查找到所有名为name的节点。不过直接使用相对路径查找要遍历所有节点,效率较低

2 访问第几个节点

XmlNodeList list = doc.SelectNodes(“//heros/hero[last()-1]/name”)

在节点后面[ ]中可以输入要访问第几个节点,注意第一个节点编号为1不是0.last()为最后一个节点的编号

3 访问前几个节点

XmlNodeList list = doc.SelectNodes(“//heros/hero[position()< 3]/name”);

在[ ]中position()可以用于访问前几个节点,上面的position()< 3代表访问1,2节点

4 根据节点属性值访问节点

XmlNodeList list = doc.SelectNodes(“//heros/hero[@id=2]/name”);

在[ ]中@id=2代表访问所有有id属性的节点中,id值为2的节点。如果直接为@id代表访问所有有id属性的节点

构建XML文件

    void createXml() {
    
    
        XmlDocument doc = new XmlDocument();
        XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", "");
        doc.AppendChild(dec);
        XmlElement rootEle = doc.CreateElement("root");
        doc.AppendChild(rootEle);
        XmlElement herosEle = doc.CreateElement("heros");
        rootEle.AppendChild(herosEle);

        string[] names = new string[] {
    
    "Superman", "Batman", "Spiderman"};
        string[] ages = new string[] {
    
    "35", "37", "20"};

        for (int i = 0; i < 3; i++) {
    
    
            XmlElement heroEle = doc.CreateElement("hero");
            herosEle.AppendChild(heroEle);

            XmlElement nameEle = doc.CreateElement("name");
            nameEle.InnerText = names[i];
            heroEle.AppendChild(nameEle);

            XmlElement ageEle = doc.CreateElement("age");
            ageEle.InnerText = ages[i];
            heroEle.AppendChild(ageEle);

            XmlAttribute id = doc.CreateAttribute("id");
            id.Value = i + "";
            heroEle.Attributes.Append(id);
        }

        doc.Save(Application.dataPath + "/XML/test2.xml");
    }

1

XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", "");

这一句用于创建XML声明,也就是XML文件开头的<?xml version="1.0" encoding="utf-8"?>

2

XmlElement rootEle = doc.CreateElement("root");
doc.AppendChild(rootEle);

创建根节点名称root,并在文件根目录添加改节点。后面添加节点的语句写法相同

3

XmlElement nameEle = doc.CreateElement("name");
nameEle.InnerText = names[i];
heroEle.AppendChild(nameEle);

对有内容的节点,使用InnerText来填充内容,再把该节点加入到其父节点。

4

XmlAttribute id = doc.CreateAttribute("id");
id.Value = i + "";
heroEle.Attributes.Append(id);

要为一个节点添加属性,首先创建XmlAttribute对象,再把该对象加入节点的Attribute中,方法和添加子节点类似

5

doc.Save(Application.dataPath + "/XML/test2.xml");

保存XML文件到指定路径

猜你喜欢

转载自blog.csdn.net/Raine_Yang/article/details/130659186