背景
这几天手上有个活,解析xml,众所周知xml的解析方法有:
- DOM
- SAX
- linq to xml
- plinq
测试用xml和生成代码
1 static void CreateFile()
2 {
3 int N = 5000000;
4 Random rand = new Random();
5 using (var writer = new XmlTextWriter("VeryHugeXmlFile.xml", Encoding.UTF8))
6 {
7 writer.Formatting = Formatting.Indented;
8
9 writer.WriteStartDocument();
10 writer.WriteStartElement("Root");
11 for (int count = 1; count <= N; count++)
12 {
13 writer.WriteStartElement("Person");
14 writer.WriteElementString("Id", count.ToString());
15 writer.WriteElementString("Name", rand.Next().ToString());
16 writer.WriteElementString("Sex", rand.Next(0, 2) == 0 ? "男" : "女");
17 writer.WriteElementString("Age", rand.Next(1, 101).ToString());
18 writer.WriteEndElement();
19 }
20 writer.WriteEndElement();
21 writer.WriteEndDocument();
22 }
23 }
之后会生成类似于下面的xml文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <Root> 3 <Person> 4 <Id>1</Id> 5 <Name>897639886</Name> 6 <Sex>女</Sex> 7 <Age>80</Age> 8 </Person> 9 <Person> 10 <Id>2</Id> 11 <Name>2012162696</Name> 12 <Sex>女</Sex> 13 <Age>60</Age> 14 </Person> 15 <Person>
测试代码
统计时间(只是粗略统计了一下运行时间)
1 static void Watch(Action<string> way, string file)
2 {
3 Stopwatch watch = new Stopwatch();
4
5 watch.Start();
6 way(file);
7 watch.Stop();
8 Console.WriteLine(watch.ElapsedMilliseconds);
9 }
DOM
1 static void DomWay(string file)
2 {
3 XmlDocument doc = new XmlDocument();
4 doc.Load(file);
5
6 Console.WriteLine(doc.SelectNodes(YOUR-XPATH-HERE).Count);
7
8 }
SAX
1 static void SaxWay(string file)
2 {
3 using (XmlTextReader reader = new XmlTextReader(file))
4 {
5 int count = 0;
6 while (reader.Read())
7 {
8 if (reader.Name == "Person" && reader.NodeType == XmlNodeType.Element)
9 {
10 reader.Read();
11 reader.Read();
12
13 int? Id = null;
14 int? name = null;
15 string sex = null;
16 int? age = null;
17
18 if (reader.Name == "Id")
19 {
20 Id = reader.ReadElementContentAsInt();
21 reader.Read();
22 name = reader.ReadElementContentAsInt();
23 reader.Read();
24 sex = reader.ReadElementContentAsString();
25 reader.Read();
26 age = reader.ReadElementContentAsInt();
27 reader.Read();
28 }
29
30 if (reader.Name == "Person" && reader.NodeType == XmlNodeType.EndElement)
31 reader.Read();
32
33 if (Id != null && name != null && sex != null && age != null)
34 {
35 if (在此设置自定义过滤条件)
36 count++;
37 }
38 }
39 }
40
41 Console.WriteLine(count);
42 }
43 }
Linq to Xml
1 static void LinqWay(string file)
2 {
3 var root = XElement.Load(file);
4 var person = from p in root.Elements("Person") 7 where 在此设置自定义过滤条件 8 select id;
9 Console.WriteLine(person.Count());
10 }
PLinq to Xml
1 static void PLinqWay(string file)
2 {
3 var root = XElement.Load(file);
4 var person = from p in root.Elements("Person").AsParallel() 7 where 在此设置自定义过滤条件 8 select id;
9 Console.WriteLine(person.Count());
10 }
统计结果
在6核8G内存机器上,测试程序设置为x64和release模式,在xml查询结果相同的情况下取运行时间(ms),没有详细采集cpu和内存数据
两个模式,区别是加了一个素数的判断。
|
Id > 5000 && sex == "男" && age > 15 && age < 50 |
Id > 5000 && sex == "男" && age > 15 && age < 50 && IsPrimeInt(name) |
|
| sax | 13857 | 40010 |
| linq | 27336 | 53760 |
| plinq | 24550 | 28846 |
| dom | 31737 | 0 |
由于dom模式本身xpath模式不支持嵌入函数,所以第二个测试没有采集结果。

小结
sax:速度优先,内存占用少,但是代码复杂度高。
linq:速度较sax慢,但是代码优雅,维护容易
plinq:同上,在非计算密集型模式中,不比linq和sax模式好多少。但是在计算密集下,后来居上
dom:速度落后,但是原生支持xpath,代码最优雅。
内存方面仅是肉眼观察了任务管理器,sax基本内存曲线为水平线,而linq&plinq在load的时候分配内存,可能其内部也是用了dom。
仓促行文,其中必有不实之处,往各位劳神指教。
来源:https://www.cnblogs.com/diggingdeeply/p/access_xml_file_ways.html