Xml是什么?
Xml全称为:Extensible Markup Lauguage;
文件的后缀名为: .xml
Xml文本编辑器
一般的文档编辑器都可以编辑xml文件,常用的打开xml文件的方式有:
1、系统自带的记事本。(本人常用)
2、专用的xml文本编辑器-XMLSprear。
3、通用的文本编辑器-Subline Text。
Xml的一些基本语法
1、<!--你要写的内容-->
这个写法相当于注释。//
2、<?xml version=“ ” encoding=“ ”?>
这个格式是固定格式,相当于交代了xml的版本和编码格式。例如UTF-8。非常important!
3、<>你要写的内容</>
xml是一个树形结构,一个根节点,后面是子节点。而编写的格式就是类似这样。
<Data>
<name>张三</name>
<age>999</age>
<item>
<id>1</id>
<num>1</num>
</item>
<item2 name="xx" id='0'/>
</Data>
4、一些特殊的符号
< -小于<
> -大于>
& -&和号
&apos -‘单引号
" -“双引号
Xml的属性语法
<!--属性就是元素标签后面的空格,添加的内容-->
<!--属性必须用引号包裹-->
<Friend name="Erden Lord" age='999'>我的宝藏</Friend>
<!--如果属性记录不想使用元素标记那就这么写如下-->
<Friend name="ghost" age='999'/>
两者写法按自己喜好来。
检查语法错误
1、元素标签必须配对
2、属性必须有引号
3、注意命名
或者在 https://www.runoob.com/xml/xml-validator.html
上面进行验证。
C#读取储存Xml
1、文件存放位置
1、只读不写文件夹下:Resource或StreamingAssets文件夹下。
2、动态储存的xml文件:Aplication.persistentDataPath 路径下。
2、读取Xml文件信息
1、XmlDocument(数据加载到内存中,方便读取)
2、XmlTextReader(以流形式加载,内存占用少,但是只能单向读取)
3、Linq
XmlDocument xml=new XmlDocument();
//通过此方法读取有两个方法,1:直接根据xml字符串内容加载
TextAsset asset=Resource.Load<TextAsset>("TestXml");
xml.LoadXml(asset.text);
//2:通过Xml文件的路径进行加载
xml.Load(Application.streamingAssetsPath + "/TestXml.xml");
3、读取元素和属性信息
XmlNode/XmlNodeList 节点信息类/节点列表信息类
//获取Xml中的根节点
XmlNode root=xml.SelectSingleNode("Data");
//再获取其下的子节点
XmlNode nodename=root.SelectSingleNode("name");
//如果想直接获取节点包裹的元素信息,直接 .InnerText
print(nodename.InnerText);
//若要是得到属性,则有Attributes
XmlNode nodeID=root.SelectSingleNode("item2");
//也有如下两个写法
print(nodeID.Attributes["id"].Value);
print(nodeID.Attributes.GetNamedItem("id").Value);
//这里是获取一个节点下具有同名的节点的方法
XmlNodeList friendlist=root.SelectNodes("Friend");
//遍历的话有for和迭代器两种方法不做展示了。
储存Xml文件
关键类:XmlDocument(用于创建节点储存文件),XmlDeclaration(用于添加版本信息),XmlElement(节点类)
//决定储存在哪个文件夹下
//1、Rsources 可读不可写,打包后找不到
//2、Application.streamingAssetsPath 可读,PC端可写,找的到
//3、Application.dataPath 打包后找不到
//4、Application.persistentDataPath 可读可写找的到
string path =Application.persistentDataPath+"/test.xml"
//创建文本对象
XmlDocument xml=new XmlDocument();
//添加固定版本信息
XmlDeclaration xmlDec=xml.CreateXmlDeclaration("1.0","UTF-8","");
//创建完成后添加进入文本对象中
xml.AppendChild(XmlDec);
//添加根节点
XmlElement root =xml.CreateElement("root");
xml.AppendChild(root);
//为根节点添加子节点
XmlElement name=xml.CreateElement("name");
name.InnerText="xxxx";
root.AppendChild(name);
//保存
xml.Save(test);
修改Xml文件
//先判断是否存在文件
if(File.Exists(path))
{
//加载后,直接添加或移除即可
XmlDocument newxml =new XmlDocument();
newxml.Load(path);
//下面两种写法
XmlNode node=newxml.SeclectSingleNode("Root").SelectSingleNode("name");
node =newxml.SelectSingleNode("Root/name");
//得到自己的父节点
XmlNode rootp=newxml.SeclectSingleNode("Root");
//移除子节点
rootp.RemoveChild(node);
}
C#中Xml的序列化/反序列化
序列化:将对象转化成可传输的字节序列过程。
反序列化:将收到或储存的的字节序列信息进行解析出来。
Xml的序列化
步骤:1、准备一个数据结构类,2、进行序列化
XmlSerializar 用于序列化对象为Xml的关键类。
StreamWriter 用于储存文件
using 用于方便流对象的创建和销毁
1、
public class Test
{
public int testpublic =1;
private int testprivate =2;
protected int testprotected =3;
Internal int testInternal =4;
public string testPublicStr ="abc";
public int TEST { get,set};
public Test2 testclass=new Test2();
}
public class Test2
{
public int test1 =1;
public float test2 =1.1f;
public bool test3=true ;
}
2、
Test ts =new Test();
//创建一个路径
string path =Application.persistentDataPath+"/Test.xml";
//写入一个文件流,如果有该文件,直接打开并修改,如果没有,就会创建一个文件
//using 括号中包裹的对象会在语句块结束后自动释放掉
//原因在于streamwriter继承自TextWriter
//TextWriter有一个IDisposable这个接口中有个方法Dispose会帮助在结束后销毁
//using一般用于 内存占用大 或 有读写操作时 进行使用。
using(streamWriter streamWrit =new streamWriter(path))
{
//进行xml文件序列化
XmlSerializer xs= new XmlSerializer (typeof(Test));
xs.Serialize(streamWrit,ts);
}
PS:1、这种方式只能存储公共的成员。
2、无法对字典类型的成员进行序列化,但List类型是可以的。
3、序列化主要用于动态存储。
自定义节点名 或 设置属性:
1、[XmlAttribute()]
2、[XmlElement()]
3、[XmlArray()]
4、[XmlArrayItem()]。
Xml的反序列化
在反序列化前,首先需要对需要反序列化的路径进行确认文件存在与否。
会用到:1、XmlSerializer的Deserialize的方法。
2、StreamReader和using。
string path =Application.persistentDataPath+"/Test.xml";
if(File.Exists(path))
{
using(StreamReader reader =new StreamReader(path))
{
XmlSerializer xs= new XmlSerializer(typeof(Test));
Test i=xs.Deserialize(reader) as Test;
}
}
反序列化的时候会对原本的List中的默认值进行添加,所以对此我们最好不要在原本的类中的List成员进行初始值赋值。
IXmlSerializable接口
这个用于解决Xml文件无法对公共字典成员序列化的问题。
C#中的XmlSerializer提供了可拓展内容,可以让一些不能被序列化和反序列化的特殊类进行处理,让这些类继承 IXmlSerializable接口实现其中的方法即可。
public class Test3 :IXmlSerializable
{
public int ts1;
public string ts2;
//返回结构
public XmlSchema GetSchema()
{
return null;
}
//反序列化时会调用这个
public void ReadXml(XmlReader reader)
{
//可以自定义反序列化规则
//1、读属性
this.ts1=int.Parse(reader["ts1"]);
this.ts2=reader["ts2"];
//2、读节点
while(reader.Read())
{
if(reader.NodeType==XmlNodeType.Element)
{
switch(reader.Name)
{
case "ts1":
reader.Read();
this.ts1=int.Parse(reader.Value);
break;
case "ts2":
reader.Read();
this.ts2=reader.Value;
break;
}
}
}
//3、读包裹节点元素
XmlSerializer s=new XmlSerializer(typeof(int));
//跳过根节点
reader.Read();
reader.ReadStartElement("ts1");
ts1=(int)s.Deserialize(reader);
reader.ReadEndElement();
}
//序列化时会调用这个
public void WriteXml(XmlWriter writer)
{
//可以自定义序列化规则
//1、写属性
writer.WriteAttributeString("ts1",this.ts1.ToString());
writer.WriteAttrbuteString("ts2",this.ts2);
//2、写节点
writer.WriteElementString("ts1",this.ts1.ToString());
writer.WriteElementString("ts2",this.ts2);
//3、写包裹节点
XmlSerializer s=new XmlSerializer(typeof(int));
writer.WriteStartElement("ts1");
s.Serialize(writer,ts1);
writer.WriteEndElement();
}
}
Test3 t=new Test3();
string path =Application.persistentDataPath+"/Test3.xml";
//序列化
using(StreamWriter writer =new StreamWriter(path))
{
XmlSerializer s =new XmlSerializer(typeof(Test3));
s.Serialize(writer,t);
}
//反序列化
using(StreamReader reader =new StreamReader(path))
{
XmlSerializer s =new XmlSerializer(typeof(Test3));
Test3 t3=s.Deserialize(reader,t) as Test3;
}