几种xml读取方法比较

背景

这几天手上有个活,解析xml,众所周知xml的解析方法有:

  1. DOM
  2. SAX
  3. linq to xml
  4. 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>

xml下载链接

测试代码

统计时间(只是粗略统计了一下运行时间)

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