7.Xml基础知识总结

7.总结


7.1 知识点

总结主要内容

学习内容回顾

优点

缺点

主要用处


7.2 核心要点速览

数据持久化与 XML 在本系列中的位置

  • 数据持久化:把游戏或应用需要「下次还能用上」的数据落到磁盘或其它存储里,进程结束、关编辑器、换场景之后仍能读回来;和「只活在内存里、一关就没了」相对。
  • XML:用成对标签嵌套表达结构和内容的标记语言,本质是纯文本,人眼可读,也容易被各种语言和工具解析;适合当配置片段、存档片段、或与外部工具/管线交换结构化数据。
  • 文件后缀:后缀是约定,用来提示「默认按什么格式去理解」;实际仍以文件内容与读写代码为准,开发时要分清「给人看的编辑体验」和「给程序解析的格式」。
  • XML 常见用途:把业务数据整理成树形结构写入文件(记录),或在模块之间、工具之间用文件或流传一份结构化描述(传输);在 Unity 里再落到放哪、怎么读、怎么写改

XML 树形结构与良构约定

  • 文档是:父子嵌套,从根到叶一层层包住,和类里「对象套对象」的直觉接近。
  • 必须有且只有一个根元素;声明、注释不算元素,不能出现多个并列顶层元素。
  • 文件头声明典型写法:<?xml version="1.0" encoding="UTF-8"?>encoding 表示按哪种编码去解析文本;读写的编码要和声明、实际保存一致,否则容易乱码。
  • 注释:<!-- ... -->,可多行;不要在里面嵌套 --
  • 元素:成对标签 <tag>...</tag> 包住子节点或文本;自闭合 <Item id="1" num="10"/> 表示没有子内容的元素。
  • 同一套数据可以写成「子元素多」或「属性多」等不同形状,只要解析规则约定清楚即可;本系列练习题里用元素名对齐字段名、集合用重复子标签、字典用键值成对出现等自建规则,团队内要统一。

属性与子元素

  • 属性写在开始标签里:属性名="值",多个属性空格分隔。
  • 教程里同一组信息可以写成「子节点 <name> / <age>」或「一个节点上 name="..." age="..."」或自闭合带属性,语义可等价,选哪种看可读性和解析方便。
  • 读属性:Attributes["名"].ValueAttributes.GetNamedItem("名").Value(属性名运行时决定时后者更顺手)。

Unity 里 XML 放哪

  • 只读、随包发布Resources(用 TextAsset + LoadXml 吃字符串)或 StreamingAssetsLoad 吃路径);正文强调 Resources 侧资源打包后不宜再当普通路径文件去捅。
  • 运行时要写入或改写:用 Application.persistentDataPath,各平台可读可写、路径稳定。
  • Application.dataPath:编辑器里看似能指到工程目录,打包后不能当存档根路径依赖

读取 XML 文件

  • 系列正文对比过:XmlTextReader 流式、单向只读、内存占用相对小,但用着别扭;LINQ to XML 另课再讲。常规读整文件、配合 SelectSingleNode / SelectNodes,用 XmlDocument 最直观。
操作 关键类/方法 代码示例 说明
创建文档对象 XmlDocument 构造函数 XmlDocument xmlDoc = new XmlDocument(); 初始化 XML 文档对象
加载字符串 XML XmlDocument.LoadXml() xmlDoc.LoadXml(textAsset.text); 从 Resources 加载文本字符串(如 TextAsset)
加载路径 XML XmlDocument.Load() xmlDoc.Load(Application.streamingAssetsPath + “/TestXml.xml”); 传入磁盘路径;只读示例用 StreamingAssets,玩家存档常在 persistentDataPath(练习里可先判本地存档再回退到 StreamingAssets 默认档)
获取根节点 XmlDocument.SelectSingleNode() XmlNode root = xmlDoc.SelectSingleNode(“Root”); XmlDocument 本身也是 XmlNode,可从文档上直接 SelectSingleNode;参数为节点路径片段(教程用法),多个同名兄弟要用 SelectNodes
获取子节点内容 XmlNode.InnerText string name = root.SelectSingleNode(“name”).InnerText; 获取节点包裹的文本(如 林文韬
获取属性值(中括号) XmlNode.Attributes[“属性名”].Value string id = node.Attributes[“id”].Value; 通过属性名直接获取属性值(如 id=”1”)
获取属性值(方法) XmlNode.Attributes.GetNamedItem() string num = node.Attributes.GetNamedItem(“num”).Value; 通过方法获取属性值(适合动态属性名)
获取同名节点列表 XmlNode.SelectNodes() XmlNodeList friends = root.SelectNodes(“Friend”); 获取指定名称的所有子节点(如多个
遍历节点列表 foreach/for 循环 foreach (XmlNode friend in friends) { Debug.Log(friend.SelectSingleNode(“name”).InnerText);} 遍历节点列表并输出子节点文本
  • 系列正文还提到 XmlTextReader:流式、单向只读、相对省内存,接口不如 XmlDocument 顺手;LINQ to XML 放在别的课讲。常规配置/存档体量用 XmlDocument 足够。

存储 XML 文件

步骤 关键类/方法 代码示例 说明
选择存储路径 Application.persistentDataPath string path = Application.persistentDataPath + “/Player.xml”; 唯一全平台可读可写路径(推荐)
创建文档对象 XmlDocument 构造函数 XmlDocument xmlDoc = new XmlDocument(); 初始化空文档
添加版本声明 XmlDocument.CreateXmlDeclaration() XmlDeclaration dec = xmlDoc.CreateXmlDeclaration(“1.0”, “UTF-8”, “”); 添加 XML 头部声明(
创建根节点 XmlDocument.CreateElement() XmlElement root = xmlDoc.CreateElement(“Root”); 创建根节点(如
添加子节点及属性 XmlElement.SetAttribute() root.SetAttribute(“id”, “1”);
XmlElement child = xmlDoc.CreateElement(“Child”);
child.InnerText = “内容”;
root.AppendChild(child);
设置属性(如 id=”1”)并添加子节点
保存文件 XmlDocument.Save() xmlDoc.Save(path); 写入磁盘(需权限,persistentDataPath 自动获得)

修改 XML 文件

操作 关键类/方法 代码示例 说明
判断文件存在 File.Exists() if (File.Exists(path)) { … } 避免空文件异常
加载现有文件 XmlDocument.Load() XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(path);
读取已存在的 XML 文件
定位子节点(路径) XmlNode.SelectSingleNode() node = doc.SelectSingleNode(“Root/atk”); 一层路径用 / 串起来,和连续 .SelectSingleNode("Root").SelectSingleNode("atk") 等价
移除节点 XmlNode.RemoveChild() XmlNode node = root.SelectSingleNode(“Child”);
if (node != null) root.RemoveChild(node);
父节点上删子节点;改完记得 Save
保存修改 XmlDocument.Save() xmlDoc.Save(path); 覆盖原文件(谨慎操作,建议备份)

路径选择对比

路径 可读 可写 打包后访问 适用场景
Resources ✔️ ❌(加密) 只读配置(如初始 XML)
StreamingAssets ✔️ 一般作只读随包资源;PC 等环境或可写但不能假定全平台可写 ✔️ 内置只读 XML、默认档;与 persistentDataPath 搭配做「无存档则用默认」
Application.persistentDataPath ✔️ ✔️ ✔️ 玩家存档(推荐)
Application.dataPath ✔️ 编辑器调试(勿用于发布)

7.3 面试题精选

基础题

1. 合法 XML 在结构上至少要满足什么

题目

面试官让你现场说几条「良构 XML」最基本的约束,你会答什么。

深入解析
  • 有 XML 声明时放在最前;元素是树形,有且只有一个根元素
  • 标签必须正确闭合;属性值要用引号包起来;注释不能乱嵌套。
  • 编码声明与实际保存一致,否则解析端可能乱码(系列里用 UTF-8 声明配合一致读写)。
答题示例

至少要有唯一根节点,标签成对或合法自闭合,属性带引号。

声明里的 encoding 要和文件真实编码一致,否则容易出现乱码。

参考文章
  • 2.XML文件格式-XML基本语法

2. LoadXml 和 Load 在 Unity 里分别怎么用

题目

XmlDocument.LoadXmlXmlDocument.Load 区别是什么,各配合什么资源放法。

深入解析
  • LoadXml字符串,典型是从 Resources.Load<TextAsset> 拿到 textAsset.text 再喂进去。
  • Load文件路径,示例里用 Application.streamingAssetsPath 指到 StreamingAssets 下的 xml;练习里读存档还会先拼 persistentDataPath
  • 二者都会把文档装进同一个 XmlDocument 内存模型,后面都用 SelectSingleNode / SelectNodes 访问。
答题示例

LoadXml 适合已经读进内存的整段 XML 字符串,比如 Resources 里的 TextAsset。

Load 适合磁盘上有真实路径的文件,教程里只读用 StreamingAssets,玩家档常用 persistentDataPath。

参考文章
  • 5.CSharp操作XML-读取XML文件

3. 节点里的文本和属性分别怎么取出来

题目

有一个 <Item id="1" num="10"/> 和一个 <name>林文韬</name>,在 XmlDocument 里怎么拿数据。

深入解析
  • 元素体里的文字用 InnerText
  • 属性在 XmlNode.Attributes 上,用 ["id"].ValueGetNamedItem("id").Value;自闭合元素同样读属性。
答题示例

子元素里的内容用 SelectSingleNode 拿到节点后读 InnerText。

属性走 Attributes,方括号或 GetNamedItem 取 Value,适合固定名或运行时拼出来的属性名。

参考文章
  • 5.CSharp操作XML-读取XML文件
  • 3.XML文件格式-XML属性

进阶题

1. 运行时写入 XML 为什么首选 persistentDataPath

题目

Resources、StreamingAssets、dataPath、persistentDataPath 存 XML 时你怎么选,理由是什么。

深入解析
  • Resources:只读,打包后不能像普通路径那样依赖文件系统去写。
  • StreamingAssets:教程强调不要默认当全平台可写,更适合随包只读资源;与 persistentDataPath 搭配做默认档可以。
  • dataPath:编辑器里好使,打包后不可靠
  • persistentDataPath:各平台可读可写、路径稳定,是运行时生成或修改 XML 的默认落点。
答题示例

要写能跟着玩家走、还能更新的文件,用 persistentDataPath。

Resources 和 StreamingAssets 主要当只读来源;dataPath 不能当发布后的存档根路径。

参考文章
  • 4.CSharp操作XML-XML文件存放位置
  • 6.CSharp操作XML-存储和修改XML文件

2. Attributes 下标和 GetNamedItem 怎么选

题目

读 XML 属性时两种写法各适合什么场景。

深入解析
  • Attributes["id"] 直观,属性名编译期就确定时常用。
  • GetNamedItem("id") 同样是官方 API,属性名来自变量或配置时更方便统一调用。
  • 都要取 .Value;空引用防护在实际项目里要自己做(正文示例为教学简洁可未写全)。
答题示例

属性名固定用中括号最省事;名字是运行时字符串用 GetNamedItem 更自然。

两种都是读 XmlAttribute,最后拿 Value。

参考文章
  • 5.CSharp操作XML-读取XML文件

3. XmlDocument 和 XmlTextReader 怎么对比

题目

除了 XmlDocument,正文还提了 XmlTextReader,各自特点是什么。

深入解析
  • XmlDocument 把整份文档建成内存树,API 和 XPath 式子节点访问好学,中小文件、配置/存档常见。
  • XmlTextReader 流式向前读,内存占用更低,但是单向只读、写法啰嗦,除非有大文件或特殊管线需求,否则系列里默认不优先。
答题示例

XmlDocument 是一次性加载成树,操作直观。

XmlTextReader 偏流式只读,省内存但不好随机跳,一般需求用 Document 就行。

参考文章
  • 5.CSharp操作XML-读取XML文件

深度题

1. 用 XML 表示 List 和 Dictionary 时要注意什么

题目

系列练习里 listIntitemDic 在 XML 里长什么样,反序列化时怎么和 C# 集合对应上。

深入解析
  • List:用容器元素包一组同名子元素(如多个 <int>),读的时候 SelectNodes 再循环 InnerText
  • Dictionary:练习用 <int> 键与 <Item> 值交替 的约定,读时分别取两个 XmlNodeList 再按下标配对;注释里提醒另一种嵌套写法要团队统一,否则同一语义多种形状难维护。
  • 这是自建映射规则,不是 XML 标准自带「字典类型」,换引擎或手改文件时最容易出错,要在工具链或校验上留余地。
答题示例

List 就是重复子节点遍历;字典这篇用键节点和值节点交错存储,读的时候两个列表按索引对齐。

规则是自己定的,项目里要统一格式,最好加校验或版本字段,避免手改 XML 对不齐。

参考文章
  • 3.XML文件格式-XML属性
  • 5.CSharp操作XML-读取XML文件

2. 修改已有 XML 时 CreateElement 要用哪个实例

题目

Load 进 XmlDocument 之后要加新节点,CreateElement 应该调在谁身上。

深入解析
  • 新节点必须属于同一份 XmlDocument,否则无法挂到已有树上;教程里 newXml.CreateElement("moveSpeed")AppendChild 到已加载的根。
  • 改结构:RemoveChild 在父节点上调用;Save 覆盖写回路径。
答题示例

一定要在加载了那份文件的 XmlDocument 上 CreateElement,保证节点属于同一文档对象。

删节点用父节点 RemoveChild,最后 Save 写盘。

参考文章
  • 6.CSharp操作XML-存储和修改XML文件

3. 多个同名兄弟节点时 SelectSingleNode 会怎样

题目

根下面有三个 <Friend>,你只调了一次 SelectSingleNode("Friend"),得到的是谁,想全取出来怎么办。

深入解析
  • SelectSingleNode 按 XPath 匹配规则取第一个匹配项;要全部用 SelectNodes 得到 XmlNodeList 再 foreach。
  • 这和「字典键唯一、列表可重复」的建模有关,面试里常顺带考你会不会把列表误当成单值读。
答题示例

SelectSingleNode 只拿第一个匹配的兄弟节点。

要遍历所有人用 SelectNodes 拿列表,再对每个节点取子字段。

参考文章
  • 5.CSharp操作XML-读取XML文件


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏