c#示例-xml序列化和xml树

这篇具有很好参考价值的文章主要介绍了c#示例-xml序列化和xml树。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

序列化

由于指针和引用类型的存在,在运行中的程序中,数据不一定是整块的。
可能东一块西一块散落在内存的各个地方。

序列,是指连续且有序的一个整体。序列化就是把数据变为连续有序整体的过程。
经过这样处理后的数据就可以方便的进行传输和储存了。

xml序列化

xml格式

xml是一种文本数据格式。用节点树的形式表示数据的名字和数据的内容。
在c#中,时间,数字,字符串及其他的基本类型内置了直接和字符串进行转化的方式。
而复杂类型会通过反射拆解他的成员,一直拆解直到只有基本类型为止。

public class Weapon//自带的序列化api要求类是public的。
{
	public (int, int) Attack { get; set; }
	public float Speed { get; set; }
	public int Level { get; set; }
}
<?xml version="1.0" encoding="utf-16"?>
<Weapon xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Attack>
    <Item1>10</Item1>
    <Item2>20</Item2>
  </Attack>
  <Speed>1.5</Speed>
  <Level>3</Level>
</Weapon>

序列化api

标准库下只提供了System.Xml.Serialization命名空间给的序列化api。
这个api不能直接序列化为string类型。只能写入到流里面。
但是我们可以使用StringWriterStringRead,这两个把字符串伪装成流的东西让他写入。

Weapon weapon = new Weapon() { Attack = (10, 20), Speed = 1.5f, Level = 3 };

// 创建一个XmlSerializer对象,传入Person类型
XmlSerializer xs = new XmlSerializer(typeof(Weapon));

// 创建一个StringWriter对象,用于保存XML字符串
StringWriter sw = new StringWriter();

// 调用XmlSerializer的Serialize方法,把Person对象序列化为XML字符串,并写入StringWriter对象
xs.Serialize(sw, weapon);

// 从StringWriter对象中获取XML字符串
string xml = sw.ToString();

// 输出XML字符串
Console.WriteLine(xml);

为了简化这个过程,可以制作扩展方法。

public static class Extension
{
	/// <summary>
	/// 将对象xml序列化为字符串
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="value"></param>
	/// <returns></returns> 
	public static string XmlSerialize<T>(this T value)
	{
		XmlSerializer xml = new XmlSerializer(typeof(T));
		StringWriter sw = new StringWriter();
		xml.Serialize(sw, value);
		return sw.ToString();
	}

	/// <summary>
	/// 将xml字符串反序列化
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="value"></param>
	/// <returns></returns>
	public static T XmlDeSerialize<T>(this string value)
	{
		XmlSerializer xml = new XmlSerializer(typeof(T));
		StringReader sr = new StringReader(value);
		return (T)xml.Deserialize(sr);
	}
}

特性控制序列化规则

这个序列化api

  • 要求目标类必须是具有public修饰的。
  • 他只会对public的成员进行序列化,包括字段和属性。
  • 他要求目标类型有一个公共无参构造器
  • 通过反射进行赋值,如果目标属性没有set访问器,或者自己没有同名元素,目标属性会保持默认值。

一些特性可以控制他的序列化规则。

元素

XmlElement特性可以指定元素名字。
在对数组或集合使用时,他会被平铺成元素。

对数组使用前

<Person>
  <Hobbies>
    <string>读书</string>
    <string>写作</string>
    <string>编程</string>
  </Hobbies>
</Person>

对数组使用后

<Person>
  <Hobbies>读书</Hobbies>
  <Hobbies>写作</Hobbies>
  <Hobbies>编程</Hobbies>
</Person>

属性

XmlAttribute特性可以让一个成员以xml属性来进行序列化。
这要求他不能是复合类型,必须像int,bool,string这样可以不拆分直接用字符串表示的类型。

对成员使用前

<Person>
  <Age>20</Age>
</Person>

对成员使用后

<Person Age="20" />

文本

XmlText特性可以让一个成员成为文本节点进行序列化。
因为文本节点没法进行区分,所以一个类下最多只能有一个成员具有这个特性。
对成员使用前

<Person>
  <Age>20</Age>
</Person>

对成员使用后

<Person>
  20
</Person>

忽略

带有XmlIgnore特性的成员在序列化和反序列化中会被无视。

排序

属性和元素的特性,可以对属性或元素命名。
此外,元素具有可选的Order属性,这个属性可以控制序列化的顺序。
但是要么全都没有这个属性,要么全部显式声明这个属性。

public class Person
{
	[XmlElement("姓名",Order =1)]
	public string Name { get; set; }
	[XmlAttribute("年龄")]
	public int Age { get; set; }
	[XmlElement(Order =0)]
	public string[] Hobbies { get; set; }
}

多态

xml可以表示更多的信息,以至于多态都可以保存。
对数组或集合使用XmlArrayItem指定类型,可以在反序列化的时候识别出类型
(序列化的时候有没有都会保存类型)。
不过你需要提前预测可能出现的所有类型并一个一个进行指定。

public class Data
{
	[XmlArrayItem("字符串", typeof(string))]
	[XmlArrayItem("数字", typeof(int))]
	public object[] Datas;
}

更多

请参阅使用属性控制 XML 序列化

xml树

对于既存的xml字符串,可以使用System.Xml.Linq命名空间下的XElement.Parse进行解析。
对于文件,流之类的东西,可以使用XElement.Load进行读取加载(参数是流或路径)。

一个XElement实例可以使用ToString查看他的xml字符串,
可以使用Save保存为文件或写入到流中。

xml节点

xml树的内容非常多,按照继承链有以下类型。

  • XObject
    • XAttribute
    • XNode
      • XComment
      • XDocumentType
      • XProcessingInstruction
      • XText
        • XCData
      • XContainer
        • XDocument
        • XElement
<?xml version="1.0" encoding="utf-8"?>
<!-- 这是一个处理指令(XProcessingInstruction),用于声明 XML 文档的版本、编码等信息 -->
<!-- This is a comment -->
<!-- 这是一个注释(XComment),用于添加一些说明性的文本 -->
<!DOCTYPE Root [
	<!-- 这是一个文档类型声明(XDocumentType),用于定义 XML 文档的结构和约束 -->
	<!ELEMENT Root (Child1, Child2)>
	<!-- 这是一个元素类型声明,用于指定 Root 元素的内容模型 -->
	<!ATTLIST Root id ID #REQUIRED>
	<!-- 这是一个属性列表声明,用于指定 Root 元素的属性 -->
]>
<Root id="R1">
	<!-- 这是一个元素(XElement),表示 XML 文档的根元素,它有一个属性(XAttribute) id,值为 R1 -->
	<Child1>Some text</Child1>
	<!-- 这是一个元素(XElement),表示 Root 元素的第一个子元素,它有一些文本内容(XText) -->
	<Child2 att="A1"/>
	<!-- 这是一个元素(XElement),表示 Root 元素的第二个子元素,它有一个属性(XAttribute) att,值为 A1 -->
	<Child3><![CDATA[在这里可以输入<>,xml,!!]]></Child3>
	<!--这是一个元素(XElement),他里面有一个CData,表示不会被转义的文本。-->
</Root>

属性

属性是在元素上面,以键值对形式的东西。
属性只能保存纯文本信息,不能表示有层级关系的内容。

XElement xel = new XElement("ele");
Console.WriteLine(xel);
var xat = new XAttribute("name", "张三");
xel.Add(xat);
Console.WriteLine(xel);
<ele />
<ele name="张三" />

从XElement实例上可以调用Attribute方法来查询指定名字的特性。
可以从获取到的Attribute上修改他,也可以从XElement直接Set指定名字的属性。

XElement xel2 = XElement.Parse(@"<ele name=""张三"" />"); 
var xat2=xel2.Attribute("name");
xat2.Value = "999";//Value只能是string类型
Console.WriteLine(xel2);

xel2.SetAttributeValue("name",true);//这个可以是任意类型,如果是null则会删除这个属性。
Console.WriteLine(xel2);

Console.WriteLine(xat2);
<ele name="999" />
<ele name="true" />
name="true"

属性也可以通过强转转为字符串,数字,时间等基础类型。

XAttribute xat3 = new XAttribute("name", "16");
float? f = (float?)xat3;
Console.WriteLine(f);

基础类型是指在xml格式中定义了的类型。是xml的基础类型而不是c#的基础类型。

注释

在xml中,使用<!---->包围的部分是注释。注释内不会要求格式。

XComment comment = new XComment("这个是注释");
Console.WriteLine(comment);
Console.WriteLine("================");
XElement xel = new XElement("root",comment); 
Console.WriteLine(xel);
<!--这个是注释-->
================
<root>
  <!--这个是注释-->
</root>

注释不保存数据信息,所以不能像属性那样使用强转来解析数据。

文档类型

文档类型是提供文档节点验证的说明。
通常会引用外部文件来要求xml符合格式。
如果内联进xml树则如下。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>

他要求note元素必须包含to,from,heading,body元素。
然后to,from,heading,body都必须是可解析的文字(不能包含嵌套的元素)。

获取文档约束需要通过文档进行解析来获取。

XDocument xDoc = XDocument.Parse(xml);//xml替换为上述的字符串

var xdt = xDoc.DocumentType; 
Console.WriteLine(xdt.InternalSubset);

验证有专门的方法,不会出现在解析的时候出现异常。
不过如何验证我没查到。

处理命令

处理命令是<??>之间的内容。
紧跟随左边的<?的文本会被解析为目标(Target)。
然后一个空格之后的所有内容(即便仍然有空格拆分多块)全部为数据(Data)。

XElement note = XElement.Parse(@"
<场景>
  <对话 text=""您想要什么?"">
    <回答 text=""红宝石"">
      <?属性 攻击力 1?>
    </回答>
    <回答 text=""蓝宝石"">
      <?属性 防御力 1?>
    </回答>
    <回答 text=""血瓶"">
      <?属性 生命 100?>
    </回答>
  </对话>
</场景>
");
var p1 = (XProcessingInstruction)note.Elements().First().Elements().First().FirstNode;
Console.WriteLine(p1.Target);//属性
Console.WriteLine(p1.Data);//攻击力 1

文本

在元素下的文本为文本节点。

XElement note = XElement.Parse(@"
<root>
  你好,世界
</root>
");
var t1 =(XText) note.FirstNode;

Console.WriteLine(t1.Value);

但是只要没有贴合元素的开闭标签,都会包含。
例如这里的标签和文字之间有换行。所以这里的文本内容会包含换行符。

转义文本

通常情况下,xml内容是不能包含尖括号,引号之类的东西。如果要书写则需要转义。
但是如果是文本元素,可以通过<![CDATA[]]>声明转义文本。
因为他的开启和结束符号很多。所以通常请看下,里面的东西都不会有歧义的解读。

XElement note = XElement.Parse(@"
<root>
  <![CDATA[这是一个xml的标签:<a int=""3"" />]]>
</root>
");
var t1 =(XCData) note.FirstNode;

Console.WriteLine(t1.Value);

这个节点只有可能是文本节点,所以这个类型是从XText派生的。

文档

文档和元素的共同基类XContainer是指里面可能嵌套东西的。
只是用来解析一个元素,使用文档和元素都可以。
但是文档另外可能包含xml开头的说明符。
<?xml version="1.0" encoding="UTF-8"?>这表示使用1.0语法的xml,使用utf-8编码。

XDeclaration declaration = new XDeclaration("1.0", "UTF-8", null);

元素

xml元素是xml树中最重要的东西,可以表示层级,可以包含内容,可以携带属性。
一个元素可以嵌套多个同名元素,所以不像json可以使用索引器访问内容。
以下示例展示xml元素的常用方法。

XElement letters = XElement.Parse(@"
<letters>
  <letter from=""张三"" to=""李四"" date=""2022-01-30"">
    <subject>问候</subject>
    <body>李四,你好!最近过得怎么样?</body>
  </letter>
  <letter from=""李四"" to=""张三"" date=""2022-02-01"">
    <subject>回复</subject>
    <body>张三,你好!我最近很好,谢谢你的关心。</body>
  </letter>
</letters>
");
foreach (var item in letters.Descendants().Where(x=>x.Name=="subject"))
{//Descendants方法可以递归获取所有子节点。
	Console.WriteLine(item.Value);
}

Console.WriteLine(letters.Elements("letter").First().Value);
//Elements方法为获取所有指定名字的直属子节点。可以不填名字。

letters.SetAttributeValue("count",4);
//SetAttributeValue方法可以修改属性的值,如果没有这个属性会添加。如果使用null值会移除属性。

元素可以使用Add方法,或者在构造器的名字后面加入多个值。

  • 如果是XObject家族的,会被嵌入进树里面。
  • 对于数组,可迭代类型的东西,会拆开后对里面的元素依次添加。
  • 其他类型的数据,会使用ToString转文字后加入进去。所以复杂类型需要自己先序列化,然后解析为xml节点,再添加xml节点。

XName

虽然在上面的例子里面,属性和节点的名字都是直接使用字符串类型。
但实际上构造器接受的是XName类型,他细分为命名空间和名字。

XElement xel = new XElement("{火蜥蜴战队}张三");
Console.WriteLine(xel);
//<张三 xmlns="火蜥蜴战队" />

XName xn = xel.Name;
Console.WriteLine(xn.NamespaceName); //火蜥蜴战队
Console.WriteLine(xn.LocalName);     //张三

XName类型的构造器是私有的。但是有一个从string而来的隐式转换。
在if语句中可以直接使用==进行判断,
但是在switch语句中,需要从他的属性里访问出他的名字。
因为隐式转换是一个操作过程,不属于常量,不能用于switch。

一个节点有明明空间时,他的子节点默认和他是相同的命名空间。
所以命名空间不同的都要标识,包括命名空间为""的。

XElement xel = new XElement("{火蜥蜴战队}张三"
	, new XElement("李四")
	, new XElement("{不死鸟战队}王五")
	, new XElement("{火蜥蜴战队}赵六"));
Console.WriteLine(xel);
/*
<张三 xmlns="火蜥蜴战队">
  <李四 xmlns="" />
  <王五 xmlns="不死鸟战队" />
  <赵六 />
</张三>
*/

用于属性上时,会再额外声明一个命名空间属性。
这个额外的命名空间属性是可以更改的。文章来源地址https://www.toymoban.com/news/detail-563383.html

XElement xel = new XElement("{火蜥蜴战队}张三"
	, new XAttribute("{2023}职务","队长")
	, new XElement("李四"
		,new XAttribute("{2023}职务","副队长")
	)
); 
Console.WriteLine(xel);
/*
<张三 p1:职务="队长" xmlns:p1="2023" xmlns="火蜥蜴战队">
  <李四 p1:职务="副队长" xmlns="" />
</张三>
*/
Console.WriteLine("===========");
xel.SetAttributeValue(XNamespace.Xmlns + "zhang", "2023");
//XNamespace.Xmlns 这个静态变量是声明命名空间的xml命名空间。和一个字符串相加以后会变成XName
Console.WriteLine(xel);
/*
<张三 zhang:职务="队长" xmlns:zhang="2023" xmlns="火蜥蜴战队">
  <李四 zhang:职务="副队长" xmlns="" />
</张三>
*/

到了这里,关于c#示例-xml序列化和xml树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 安卓数据存储补充:XML序列化

    序列化是将对象状态转换为可保存或传输的格式的过程。我们可以把对象序列化为不同的格式,比如说:JSon序列化、XML序列化、二进制序列化等等,不同的形式适应不同的业务需求。 把对象的成员变量转化为XML格式,需要使用Xml序列化器(XmlSerializer类),序列化之后的对象

    2024年02月10日
    浏览(10)
  • C#: Json序列化和反序列化,集合为什么多出来一些元素?

    C#: Json序列化和反序列化,集合为什么多出来一些元素?

    如下面的例子,很容易看出问题: 如果类本身的无参构造函数, 就添加了一些元素,序列化,再反序列化,会导致元素增加。 如果要避免,必须添加: new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace }

    2024年02月10日
    浏览(10)
  • C#使用MongoDB-第二章 序列化

    C#使用MongoDB-第二章 序列化

    这里在C#中所使用的连接MongoDB数据库的依赖库为 MongoDB.Driver ,使用前先到Nuget中进行安装。 默认情况下,在我们对MongoDB数据库进行CRUD时,MongoDB.Driver(以后简称驱动库)会自动为我们根据属性、属性类型,将实体类型转换为对应的BSON。 实体类 对应的BSON 1、主键Id 默认情况

    2024年01月22日
    浏览(12)
  • C#对象二进制序列化优化:位域技术实现极限压缩

    目录 1. 引言 2. 优化过程 2.1. 进程对象定义与初步分析 2.2. 排除Json序列化 2.3. 使用BinaryWriter进行二进制序列化 2.4. 数据类型调整 2.5. 再次数据类型调整与位域优化 3. 优化效果与总结 在操作系统中,进程信息对于系统监控和性能分析至关重要。假设我们需要开发一个监控程序

    2024年01月22日
    浏览(9)
  • Protobuf-net:C#高效序列化工具,助力接口传输与前端解析

    Protobuf-net:C#高效序列化工具,助力接口传输与前端解析

      概述: Protobuf-net是C#中高效的二进制序列化工具,以紧凑、跨语言支持和卓越性能著称。通过定义消息类型、序列化和反序列化实现数据传输,并可适用于Web接口。前端可使用protobuf.js库解析Protobuf格式数据。 Protobuf-net(Protocol Buffers)是一种高效的二进制序列化工具,具有

    2024年03月09日
    浏览(12)
  • Go语言网络编程入门:TCP、HTTP、JSON序列化、Gin、WebSocket、RPC、gRPC示例

    Go语言网络编程入门:TCP、HTTP、JSON序列化、Gin、WebSocket、RPC、gRPC示例

    在本文中,我们将介绍Go语言中的网络编程的不同方式,包括TCP、HTTP、Gin框架、WebSocket、RPC、gRPC的介绍与连接实例,并对所有示例代码都给出了详细的注释,最后对每种模式进行了总结。 TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,提供

    2024年02月16日
    浏览(15)
  • 【Java万花筒】选择最适合您的数据序列化格式:比较 Avro、Protocol Buffers、JSON、XML、MessagePack和BSON

    在当今数据驱动的世界中,高效地处理和传输数据变得至关重要。选择合适的数据序列化格式对于数据存储、通信和处理的性能至关重要。本文将介绍并比较几种常用的数据序列化格式,包括Apache Avro、Protocol Buffers、JSON、XML、MessagePack和BSON。通过了解它们的概述、特点、应用

    2024年02月20日
    浏览(14)
  • 【序列化与反序列化】关于序列化与反序列化MessagePack的实践

    【序列化与反序列化】关于序列化与反序列化MessagePack的实践

    在进行序列化操作之前,我们还对系统进行压测,通过 jvisualvm 分析cpu,线程,垃圾回收情况等;运用火焰图 async-profiler 分析系统性能,找出程序中占用CPU资源时间最长的代码块。 代码放置GitHub:https://github.com/nateshao/leetcode/tree/main/source-code/src/main/java/com/nateshao/source/code/ser

    2024年02月11日
    浏览(11)
  • 【网络】序列化反序列化

    【网络】序列化反序列化

    在前文《网络编程套接字》中,我们实现了服务器与客户端之间的字符串通信,这是非常简单的通信,在实际使用的过程中,网络需要传输的不仅仅是字符串,更多的是结构化的数据(类似于 class , struct 类似的数据)。 那么我们应该怎么发送这些结构化的数据呢? 如果我们

    2024年02月05日
    浏览(13)
  • 序列化,反序列化之实例

    序列化,反序列化之实例

    介绍文章 __construct() 当一个对象创建时自动调用 __destruct() 当对象被销毁时自动调用 (php绝大多数情况下会自动调用销毁对象) __sleep() 使**用serialize()函数时触发 __wakeup 使用unserialse()**函数时会自动调用 __toString 当一个对象被当作一个字符串被调用 __call() 在对象上下文中调用不

    2024年02月14日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包