简介

在.NET framework 中存在大量操作xml数据的类库和api,但在.NET framework 3.5后我们的首选一般就是linq to xml。

linq to xml操作xml数据无论是XElement.Load方法还是XElement.Parse方法都会将整个xml文件加载到内存中,在xml文件超级大的情况下linq to xml就不太适合。

对于大型的xml文件最好的方法就是每次只读取一部分,这样逐渐的读取整个xml文件,这个刚好对应XmlReader类。

XmlReader使用起来效率高,但操作没有linq to xml方便,所以就希望取两者之长:既有效率使用起来也如linq to xml一样方便。

思路

XElement类有一个方法ReadFrom,此方法接受一个XmlReader参数 : XNode.ReadFrom 方法 (XmlReader)

在上面的链接MSDN上,其实已经有了对应的组合方式了,而且名字也不错:执行大型 XML 文档的流式转换

static IEnumerable<XElement> StreamXElements(string uri, string matchname)
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreWhitespace = true; using (XmlReader reader = XmlReader.Create(uri, settings))
{
reader.MoveToContent();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == matchname)
{
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
{
yield return el;
}
}
break; }
}
}
}

以上代码就是用XmlReader一直Read下去,然后碰到XmlNodeType.Element类型时就可以XElement.ReadFrom(reader)构建XElement,最重要的就是最后的yield return。

这样目前为止,so far so good.

但在测试的时候,发现此方法有一个比较严重的bug,每次读取一个XElement之后就会跳过一个XElement:

aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAANkAAACnCAIAAAAT9G6QAAAJHElEQVR4nO2dvXHsNhSF4Qo8L3EDnjeuwQifK3guAnUodGZknHEDijZlAVvEJixBiZ05wwvAH/xcUuDP7r0EzzcMJAgEoOXRIcDF0SoHgAwU9wAA6IEWgRSgRSAFaBFIAVoEUoAWgRSgRSAFaBFIAVoEUpClxYdRb0q9KXVrd7bU3pS+dwf13tnmgCGBT9iqxdb4y+aPxq687Et0d32gFttbMM43bT+29L5F2cOJQe8Gcl5inRY765RxzjnXmuC6trcjbeNwLY4yKmn5kN7zYXhzNY+V508v+AVYocXWOKVdN3wTeszD9NY43uZGExp/5KIT25vSjSbtKlVD3uZc4YfVgVvnWlwa56e9RwLtbDN1ZB7+95qk1t2174jWYjROcvCBg0Yve9WUatHq+A801uKH1W+mjf/0+4v6YfVwVYZrZtrYSpM7YKwGqs2Y4fSoJuWLnW2ImkmbZBdEnWxaEtSZ2o/u0cHvm/e+5MeddUq56m/wRVo0yqVTHVKLvc6mwsZ2fWFr/MUIpDnqb1GLZJtDtcgC02lDPl8cepltM+udLqSnjx9W+wH0r0ZQc/yRc4mnBhodyunJd+uUckdOy+VR6otGOW2D76MLP/gEeePubKPtw+qbtY22d+Nf+jVaJCYDlK3OajHTzcwEg+idLpxbyvjy7q7zXy2w0s42S0uo7q6zNdYFhOhWzRej23RwOT+s7qdK403QuUgN2ty0ebjurnWjc4l8eo/OaoY32da8TYV9zYeh54tLbZK9zxQ+DL0ofhjVaE39SYQTys+WevEq5yI3aLdrHU3O/YPy4eXu7rq/cpNqaS2Gt934lpq2GSw+jB19aJz+N7a9E6IPmBtn2vvMkKLyYHXc2Sa6yaar+P5H0RMxf3rU0dgC1tFgK9FqGqwDWjwOvD2zD2jxGB5GwRF3Ai0CKUCLQArQIpACtAikAC0CKUCLQArQIpACtAikcFYtvjSbgjdUXoIoLfJmU8J9h9vaPDafcDn4tRhsReHNpixosRBiPJfaaLMTZi3GYQ7ebAqtRbLNPJsSDTLaXXahwMpOOLWYZmiYsykLvljS70L5hfbD7oFNi0SGhjmbUq7FuWzK4pzhGjmBPXD6YpqhYc6mrNFiUJ7kfmgtQogFMM8X49s0bzZlgxaJKUSe4sMNuhCx6+iAF2VTkqj/FFte7ij9TwRx71hHl8OvRTaQTRHGVbWIt1LkcUUtIpsikytqEcgEWgRSYNOiUvgzABEQBJACfBFIAYIAUoAvAilAEEAILXxxQsLnuwT/V/JqbwrxafFV8GZokq0Vn73ZE2+Q20BrlFJq+GfhRsX48s7qtGhFYVSmp/9ZSpxODCkdVFi1Ul+Uk6HJxrBEYeBmdu9Pa5S21iiijc7qvrg1k4TGr8sL0+662TbJIbUmkmXYZo2+KCpDk4/BzX+2Ta7FuXFSGZr+0raUFknZeDPrzyksTBr1Xc3WzIfUWR2MpG5flJahScfQf0t9CEP+QRuLn22TbNEN3SzV4mSK45ed1Upp21qtTFteGL2yQ49zNWeGNN6lk2HW5YsCMzRU/dnPcEhPXBqnrzBEFwJnyrUY3gs7q5XWWk0y0rYrL5xekcnf6DbnhtQar8LWpE5bnS9Ky9BQ9ddocXacUYYmW6Uky4rElSYJTDfRwsKxyWimR9SkhxQNJh1ZVb7oEZWhoboo1uL8OBcyNIkvprOysCBa0BQWZkKcr0kMKTpZjBY51tEBL8rQkM90irVIj/OTDE2kRUo4oYtONUsLU7/Lnx+RK6fIDOmqNfoiJ8jQbKdSX+QBGZpdwBcPAhma3cAXgRggCCCFE/ji+x9/2i9fcVR8vH/77k7hi3///Kv98vWvn37BUfHhTuGLfqz///sfjioPfi2WM44VVAm/Ftf64lMHAxjh12I50GLdDNf3DM8XX6ZF5F1Y4NdiOfu0iLxLuhVBTt7Fn86vxaf6IvIu+Tki8i7RNrG+Jr8Wy1mrReRd5OZdIqH2wuTX4pN8EXkX0XmXaD9lr2V+LZZTrkXkXZz4vEswtdS6bl9E3oVaVojJu8Qvl5covxbLWTtfRN5Fbt4l/N2GZvi1yLGODkDeJXn88qK8y3SHHqvxa7GcM73vgrzLevi1+FRf5AF5l03wa7GcU2gReZfN8GuxQl8Em8A+HSAFfi2u9UUcdR/uFL74/u07+yuF46nHP7/97k7hi+AiQBBACvBFIAUIAgjhDM8XXwbyLqyc4X2XfSDvku5jeFneJeo/3vhNbaOo1BeRd8nPeX3ehdoqttBmjb6IvIuQvAsxkqU2q/NF5F1E5V2SO/Rim3X5IvIuTk7eJRnBqMHZmtX5IvIu1LKCIe+SvDJ92VLNunzRg7yLtLxLPF2dq1mdL3qQdxmr8uVdwqc3iTFTj3Sq9EVOkHfZTqW+yAPyLruALx4E8i67gS8CMUAQQArwRSAFCAJIAb4IpABBACnAF4EUIAggBDxfDEDehZX633dB3iXdx8CbdxmL8y0bdfoi8i75OZLyLvT2oQp9EXkXuXmX8eUTpcUn+SLyLpLzLuGABGnxGSDv4mTnXaizp0q1+SLyLtSyQkzexdEN+DpV+aIHeRfBeRc3VhKkRY51dADyLtHjl5flXaKHPyoOwlToi5wg77KdSn2RB+RddgFfPAjkXXYDXwRigCCAFOCLQAoQBJACfBFIAYIAUoAvAilAEEAIeL4YgLwLK/W/74K8S7oRgTXvQp/uq9fpi8i75OfIyLuQp/ffV+iLyLuIz7vEpw/f1+aLyLucIe8SnT4WVOWLyLu4c+Rd6M3htfki8i7UskJW3oXcbF6bL3qQd5Gcd5kRoqvQFz3Iu4xVheVdZk53rk5f5AR5l+1U6os8IO+yC/jiQSDvshv4IhADBAGkAF8EUoAggBTgi0AKEASQAnwRSAGCAELA88UA5F1Yqf99F+Rd0o0IvJ/vEhZK2Uv7VF9E3iU/B3kXBpB3OUXeJdvoWJ0vIu8iPu8yFKejrMsXkXdxJ8m79GfVnQNE3oVaVsjKu8wU1uWLHuRdJOddwt9O1+2LHuRdxqqC8y7JwGr0RU6Qd9lOpb7IA/Iuu4AvHgTyLruBLwIxQBBACvBFIAUIAkgBvgik8AMeU9Al42Ag7gAAAABJRU5ErkJggg==" alt="" />

如以上的xml,在读取第一个470002048节点之后,470002049节点就被跳过了。

这里其实就是XmlReader不小心Read too far的一个问题,read too far其实就是多read了一次,可以这样理解:

initial read;
(while "we're not at the end") {
do stuff;
read;
}

再回到我们上面的代码,其实在XElement.ReadFrom(reader)构建XElement之后,内部已经read了一次,但在while语句中我们还是在reader,这样下一个XElement是不会读到的。

那知道原因之后,解决起来也简单了,这里就用reader.EOF 做判断条件并去掉多余的一次read,具体代码如下:

static IEnumerable<XElement> StreamXElements(string uri, string matchname)
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreWhitespace = true; using (XmlReader reader = XmlReader.Create(uri, settings))
{
reader.MoveToContent();
while (!reader.EOF)
{
if (reader.NodeType == XmlNodeType.Element
&& reader.Name == matchname)
{
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
{
yield return el;
}
}
else
{
reader.Read();
}
}
}
}

总结

组合XmlReader和XElement的方式在MSDN中其实已经有了相应的文章介绍,但自己摸索的过程中还是有很多的收获,参考文章如下:

http://stackoverflow.com/questions/2299632/why-does-xmlreader-skip-every-other-element-if-there-is-no-whitespace-separator

https://msdn.microsoft.com/en-us/library/mt693229.aspx

http://stackoverflow.com/questions/2441673/reading-xml-with-xmlreader-in-c-sharp

https://blogs.msdn.microsoft.com/xmlteam/2007/03/24/streaming-with-linq-to-xml-part-2/

XmlReader和XElement组合之读取大型xml文档的更多相关文章

  1. 如何:执行大型 XML 文档的流式转换 大XML文件解析入库的一个方法

    w Parsing Huge XML Files Incrementally http://pclib.github.io/safari/program/python-cookbook/Text/ch ...

  2. Java获取XML节点总结之读取XML文档节点

    dom4j是Java的XML API,用来读写XML文件的.目前有很多场景中使用dom4j来读写xml的.要使用dom4j开发,需要下载导入dom4j相应的jar文件.官网下载:http://www. ...

  3. 读取XML文档存入泛型List<T>集合中

    前一篇博文是<泛型List<T>转存为XML文档> http://www.cnblogs.com/insus/p/3277410.html 把一个List<T>集合 ...

  4. java中XML操作:xml与string互转、读取XML文档节点及对XML节点增删改查

    一.XML和String互转: 使用dom4j程式变得很简单 //字符串转XML String xmlStr = \"......\"; Document document = D ...

  5. XML文档

    XML(Extensible Markuo Language)可标记扩展语言.它是一种以简单文本格式存储数据的方式,可以被任何计算机读取. XML文档里包含的元素都是可以自定义的. 1.XML文档声明 ...

  6. Anakia 转换xml文档为其他格式

    一.简介 Anakia 使用JDOM 和Velocity将XML文档转换为特定格式的文档 二.解析xml文档方法 1.DOM java jdk,xml-api.jar 需要加载整个xml文档来构建层次 ...

  7. Java高级特性 第15节 解析XML文档(3) - JDOM和DOM4J技术

    一.JDOM解析 特征: 1.仅使用具体类,而不使用接口. 2.API大量使用了Collections类. Jdom由6个包构成: Element类表示XML文档的元素 org.jdom: 解析xml ...

  8. 使用JAXP对xml文档进行DOM解析基础

    XML解析方式分为两种:dom和sax         dom:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式.       sax: ...

  9. js 将XML字符串解析成XML文档 --- attribute construct error--- 空白字符与空格问题

    最近在做xml在线编辑器,遇到一个字符串解析成xml文档的问题,记录一下. 原始xml内容读取自xml文档 <label class="test" id="labe ...

随机推荐

  1. 初识WEB:输入URL之后的故事

    1. 概述2. HTTP请求过程3. 相关性能检测及优化手段4. 浏览器的呈现过程5. 浏览器的呈现引擎6. 引用及延伸阅读 概述 为什么输入www.cnblogs.com之后敲一个回车,浏览器就会显 ...

  2. 从“差不多了”到 正式发布 -- 新浪微博WinPhone UWP版诞生记

    本文粗略记述了UWP团队从接手新浪微博项目到发布第一版的过程.本文不是技术贴,而是回顾“软件工程周期失控是一种怎样的体验”. 接手新项目:捡了个大便宜 2016年1月份,UWP team开始接手新浪微 ...

  3. Net作业调度(三) — Quartz.Net进阶

    介绍 前面介绍Quartz.Net的基本用法,但在实际应用中,往往有更多的特性需求,比如记录job执行的执行历史,发邮件等. 阅读目录 Quartz.Net插件 TriggerListener,Job ...

  4. MySQL 权限

    create user创建用户 CREATE USER li@localhost IDENTIFIED BY 'li'; 授予用户li数据库person的所有权限,并允许用户li将数据库person的 ...

  5. Go语言的堆栈分析

    本文为理解翻译,原文地址:http://www.goinggo.net/2015/01/stack-traces-in-go.html Introduction 在Go语言中有一些调试技巧能帮助我们快 ...

  6. linux split 及优化

    split 虽然不好用, 但是还是可以用一下的! 有两个方式拆分, 按固定的行数, 按固定的大小. 默认是 1000 行, 后缀长度为2, 后缀长度N是说, 分片从N个字母/数字 的最小值 到 其最大 ...

  7. thinphp框架的项目svn重新检出后的必备配置

    刚刚试着去了解thinkphp框架,在这里做一些笔记,后续有新的总结会更新到这里,如有错误与遗漏,望大家指正. 用thinkphp框架的项目,在用svn重新检出之后,需要进行一些基本配置,方可在本地打 ...

  8. Security3: Schema 和 Permission

    Schema是Object的容器,授予对Schema访问的权限,就是授予对Schema下所有object的访问权限. 一,Schema 是object的container The new schema ...

  9. HTML5系列:HTML5绘图

    1. canvas元素基础 canvas元素是HTML5中新增的一个重要元素,专门用来绘制图形. 在页面中使用canvas元素绘制图形需要经过的三个步骤: 步骤一  使用canvas元素创建一个画布区 ...

  10. Unity 文件读取

    存储: 在程序发布后文件的存放有两种,第一种是打包到Uniyt的资源包中(*.unity3D),第二种就是把文件存放在一个特殊的目录如:StreamingAssets,这个目录的东西Unity不会打包 ...