C# 中简单的 PList 解析器
一个用 100 行 C# 代码实现的简单 plist 解析器。
引言
最近我负责在工作中开发一个纹理打包工具。我们使用纯 C# (4.0) 来编写我们的工具。我需要在我的代码中读取和解析 plist 文件。我在互联网上搜索过,但不幸的是,似乎缺少 C# 中的 plist 解析器。通过阅读几个示例文件,我很快就理解了 plist 语法,因为它对于人类来说很容易分析,对于解析器来说也很容易识别。我决定重新造这个轮子。
直接看代码
实现非常简单,我大约在一个小时内完成了它。让我们快速看一下整个代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Data
{
public class PList : Dictionary<string, dynamic>
{
public PList()
{
}
public PList(string file)
{
Load(file);
}
public void Load(string file)
{
Clear();
XDocument doc = XDocument.Load(file);
XElement plist = doc.Element("plist");
XElement dict = plist.Element("dict");
var dictElements = dict.Elements();
Parse(this, dictElements);
}
private void Parse(PList dict, IEnumerable<XElement> elements)
{
for (int i = 0; i < elements.Count(); i += 2)
{
XElement key = elements.ElementAt(i);
XElement val = elements.ElementAt(i + 1);
dict[key.Value] = ParseValue(val);
}
}
private List<dynamic> ParseArray(IEnumerable<XElement> elements)
{
List<dynamic> list = new List<dynamic>();
foreach (XElement e in elements)
{
dynamic one = ParseValue(e);
list.Add(one);
}
return list;
}
private dynamic ParseValue(XElement val)
{
switch (val.Name.ToString())
{
case "string":
return val.Value;
case "integer":
return int.Parse(val.Value);
case "real":
return float.Parse(val.Value);
case "true":
return true;
case "false":
return false;
case "dict":
PList plist = new PList();
Parse(plist, val.Elements());
return plist;
case "array":
List<dynamic> list = ParseArray(val.Elements());
return list;
default:
throw new ArgumentException("Unsupported");
}
}
}
}
是不是很清晰?
LINQ 和 dynamic
类型使这个轻量级类受益匪浅。如果没有它们,就需要更多的代码行。这个类是一个递归数据结构,虽然我们看不到其中定义了 PList
属性;它的基类是 Dictionary<string, dynamic>
,其中的值可以是 string/int/float/bool/PList/List<dynamic>
的值。解析方法是递归的,因为其结构是递归的。Parse
方法枚举 XML 数据中的所有键值对,并将解析后的字符串-动态对填充到 PList
结构中;每一步它都会调用 ParseValue
方法来解析一个值;ParseValue
方法根据 XML 节点名称中指示的类型,调用数据转换方法或 ParseArray
或 Parse
递归地调用。ParseArray
方法枚举所有子 XML 节点,并通过递归调用 ParseValue
将它们解析为动态类型。当然,我们可以使用 object
代替 dynamic
,但我们必须在从 PList
中检索值时添加更多的类型区分,这是我希望避免的。
使用代码
要解析 plist 文件,只需编写如下代码:
PList plist = new PList();
plist.Load("file_path.plist");
或
PList plist = new PList("file_path.plist");
检索解析后的数据与使用泛型 Dictionary
相同,因为 PList
派生自 Dictionary<string, dynamic>
。代码可能看起来粗糙,因为我只想在这里展示主要思想,而不想加入干扰信息。我认为您应该并且应该在使用之前对其进行完善,例如添加一些错误/异常处理,或者添加一个序列化方法等。这些可以是非常简单的任务。
玩得开心!
用 C# 编写 plist 解析器比我预期的更容易,并且对我来说效果很好。我希望它也能帮助你。