这几天手上有个活,解析xml,众所周知xml的解析方法有:
- DOM
- SAX
- linq to xml
- plinq
测试用xml和生成代码
@H_301_20@ 1 static void CreateFile() @H_301_20@ 2 { @H_301_20@ 3 int N = 5000000; @H_301_20@ 4 Random rand = new Random(); @H_301_20@ 5 using (var writer = new XmlTextWriter("VeryHugeXmlFile.xml",Encoding.UTF8)) @H_301_20@ 6 { @H_301_20@ 7 writer.Formatting = Formatting.Indented; @H_301_20@ 8 @H_301_20@ 9 writer.WriteStartDocument(); @H_301_20@10 writer.WriteStartElement("Root"); @H_301_20@11 for (int count = 1; count <= N; count++) @H_301_20@12 { @H_301_20@13 writer.WriteStartElement("Person"); @H_301_20@14 writer.WriteElementString("Id",count.ToString()); @H_301_20@15 writer.WriteElementString("Name",rand.Next().ToString()); @H_301_20@16 writer.WriteElementString("Sex",rand.Next(0,2) == 0 ? "男" : "女"); @H_301_20@17 writer.WriteElementString("Age",rand.Next(1,101).ToString()); @H_301_20@18 writer.WriteEndElement(); @H_301_20@19 } @H_301_20@20 writer.WriteEndElement(); @H_301_20@21 writer.WriteEndDocument(); @H_301_20@22 } @H_301_20@23 }
@H_301_20@ 1 <?xml version="1.0" encoding="utf-8"?> @H_301_20@ 2 <Root> @H_301_20@ 3 <Person> @H_301_20@ 4 <Id>1</Id> @H_301_20@ 5 <Name>897639886</Name> @H_301_20@ 6 <Sex>女</Sex> @H_301_20@ 7 <Age>80</Age> @H_301_20@ 8 </Person> @H_301_20@ 9 <Person> @H_301_20@10 <Id>2</Id> @H_301_20@11 <Name>2012162696</Name> @H_301_20@12 <Sex>女</Sex> @H_301_20@13 <Age>60</Age> @H_301_20@14 </Person> @H_301_20@15 <Person>
测试代码
统计时间(只是粗略统计了一下运行时间)
@H_301_20@1 static void Watch(Action<string> way,string file) @H_301_20@2 { @H_301_20@3 Stopwatch watch = new Stopwatch(); @H_301_20@4 @H_301_20@5 watch.Start(); @H_301_20@6 way(file); @H_301_20@7 watch.Stop(); @H_301_20@8 Console.WriteLine(watch.ElapsedMilliseconds); @H_301_20@9 }
DOM
@H_301_20@1 static void DomWay(string file) @H_301_20@2 { @H_301_20@3 XmlDocument doc = new XmlDocument(); @H_301_20@4 doc.Load(file); @H_301_20@5 @H_301_20@6 Console.WriteLine(doc.SelectNodes(YOUR-XPATH-HERE).Count); @H_301_20@7 @H_301_20@8 }
SAX
@H_301_20@ 1 static void SaxWay(string file) @H_301_20@ 2 { @H_301_20@ 3 using (XmlTextReader reader = new XmlTextReader(file)) @H_301_20@ 4 { @H_301_20@ 5 int count = 0; @H_301_20@ 6 while (reader.Read()) @H_301_20@ 7 { @H_301_20@ 8 if (reader.Name == "Person" && reader.NodeType == XmlNodeType.Element) @H_301_20@ 9 { @H_301_20@10 reader.Read(); @H_301_20@11 reader.Read(); @H_301_20@12 @H_301_20@13 int? Id = null; @H_301_20@14 int? name = null; @H_301_20@15 string sex = null; @H_301_20@16 int? age = null; @H_301_20@17 @H_301_20@18 if (reader.Name == "Id") @H_301_20@19 { @H_301_20@20 Id = reader.ReadElementContentAsInt(); @H_301_20@21 reader.Read(); @H_301_20@22 name = reader.ReadElementContentAsInt(); @H_301_20@23 reader.Read(); @H_301_20@24 sex = reader.ReadElementContentAsString(); @H_301_20@25 reader.Read(); @H_301_20@26 age = reader.ReadElementContentAsInt(); @H_301_20@27 reader.Read(); @H_301_20@28 } @H_301_20@29 @H_301_20@30 if (reader.Name == "Person" && reader.NodeType == XmlNodeType.EndElement) @H_301_20@31 reader.Read(); @H_301_20@32 @H_301_20@33 if (Id != null && name != null && sex != null && age != null) @H_301_20@34 { @H_301_20@35 if (在此设置自定义过滤条件) @H_301_20@36 count++; @H_301_20@37 } @H_301_20@38 } @H_301_20@39 } @H_301_20@40 @H_301_20@41 Console.WriteLine(count); @H_301_20@42 } @H_301_20@43 }
Linq to Xml
@H_301_20@ 1 static void LinqWay(string file) @H_301_20@ 2 { @H_301_20@ 3 var root = XElement.Load(file); @H_301_20@ 4 var person = from p in root.Elements("Person")@H_301_20@ 7 where 在此设置自定义过滤条件@H_301_20@ 8 select id; @H_301_20@ 9 Console.WriteLine(person.Count()); @H_301_20@10 }
PLinq to Xml
@H_301_20@ 1 static void PLinqWay(string file) @H_301_20@ 2 { @H_301_20@ 3 var root = XElement.Load(file); @H_301_20@ 4 var person = from p in root.Elements("Person").AsParallel()@H_301_20@ 7 where 在此设置自定义过滤条件@H_301_20@ 8 select id; @H_301_20@ 9 Console.WriteLine(person.Count()); @H_301_20@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模式好多少。但是在计算密集下,后来居上
内存方面仅是肉眼观察了任务管理器,sax基本内存曲线为水平线,而linq&plinq在load的时候分配内存,可能其内部也是用了dom。
仓促行文,其中必有不实之处,往各位劳神指教。