近期有个任务要求处理大XML文件,其中有个存了Base64的大节点(>90M,路径已知)。

这种任务只能上XmlReader,即使如此大节点的处理还是头疼了一阵……

最初查MSDN的时候,找到了ReadChars(),可以拿来对付大节点。

方法说明:https://msdn.microsoft.com/zh-cn/library/system.xml.xmltextreader.readchars(v=vs.110).aspx

示例中提到使用方法是:

while(0 != reader.ReadChars(buffer, 0, 1))
{// Do something.// Attribute values are not available at this point.
}

这个处理规范格式的XML没有问题,比如这样的:

<Root><LeafNode>Value</LeafNode><ParentNode><LeafNode>Value</LeafNode></ParentNode>
</Root>

但是(没人喜欢这个词,然并卵……),遇到些格式诡异的XML就……

<Root><LeafNode>Value</LeafNode><ParentNode>
<LeafNode>Value</LeafNode></ParentNode>
</Root>

比如这个画风的,用示例代码去读第一个LeafNode的内容,估计会读出“ValueValue”来……

偏偏输入的XML就是这风格的……(*sigh*)

单步执行了一阵,发现这种情况下,XmlTextReader.Name会变化成下个节点的名称(XmlTextReader.LocalName亦如此),可以根据这个判断是否已经达到节点结尾。

改进版为:

string currentName = reader.LocalName;
while(currentName == reader.LocalName && 0 != reader.ReadChars(buffer, 0, 1))
{// Do something.// Attribute values are not available at this point.
}

顺便贴上一个转写并对特定节点进行处理的代码:

List<string> processNodePathList = new List<string> {"/Root/Path/to/Target"};
List<string> bigNodePathList = new List<string> { "/Root/Path/to/Big/Node" }; private static void ProcessBigXmlFile(string sourcePath, string targetPath, IList<string> processNodePathList, IList<string> bigNodePathList)
{var processNodeNameList =processNodePathList.Select(processNodePath => processNodePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)).Select(nodePathParts => nodePathParts[nodePathParts.Length - 1]).ToList();var bigNodeNameList = bigNodePathList.Select(bigNodePath => bigNodePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)).Select(nodePathParts => nodePathParts[nodePathParts.Length - 1]).ToList();var sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read);var reader = new XmlTextReader(sourceStream);var targetStream = new FileStream(targetPath, FileMode.Create, FileAccess.Write);var writer = new XmlTextWriter(targetStream, Encoding.UTF8);try{var pathStack = new Stack<string>();var readResult = reader.Read();while (readResult){int skipMode = 0;switch (reader.NodeType){case XmlNodeType.Element:{pathStack.Push(reader.Name);writer.WriteStartElement(reader.LocalName);if (reader.HasAttributes){while (reader.MoveToNextAttribute()){writer.WriteAttributeString(reader.LocalName,reader.Value);}reader.MoveToElement();}if (processNodeNameList.Contains(reader.LocalName)){var index = processNodeNameList.IndexOf(reader.LocalName);if (CompareNodePath(pathStack, processNodePathList[index])){// Replace node content
writer.WriteFullEndElement();skipMode = 1;}}else if (bigNodeNameList.Contains(reader.LocalName)){var index = bigNodeNameList.IndexOf(reader.LocalName);if (CompareNodePath(pathStack, bigNodePathList[index])){reader.MoveToContent();var buffer = new char[1024];int len;while (reader.LocalName == bigNodePathList[index] &&(len = reader.ReadChars(buffer, 0, buffer.Length)) > 0){writer.WriteRaw(buffer, 0, len);}writer.WriteFullEndElement();skipMode = 2;}}if (reader.IsEmptyElement){pathStack.Pop();writer.WriteEndElement();}break;}//case XmlNodeType.Attribute://{//    newPackageWriter.WriteAttributeString(oldPackageReader.LocalName, oldPackageReader.Value);//    break;//}case XmlNodeType.Text:{writer.WriteValue(reader.Value);break;}case XmlNodeType.CDATA:{writer.WriteCData(reader.Value);break;}//case XmlNodeType.EntityReference://{//    newPackageWriter.WriteEntityRef(oldPackageReader.Name);//    break;//}//case XmlNodeType.Entity://{//    break;//}case XmlNodeType.ProcessingInstruction:{writer.WriteProcessingInstruction(reader.Name, reader.Value);break;}case XmlNodeType.Comment:{writer.WriteComment(reader.Value);break;}//case XmlNodeType.Document://{//    break;//}case XmlNodeType.DocumentType:{writer.WriteRaw(string.Format("<!DOCTYPE{0} [{1}]>", reader.Name,reader.Value));break;}//case XmlNodeType.DocumentFragment://{//    break;//}//case XmlNodeType.Notation://{//    break;//}case XmlNodeType.Whitespace:{writer.WriteWhitespace(reader.Value);break;}//case XmlNodeType.SignificantWhitespace://{//    break;//}case XmlNodeType.EndElement:{pathStack.Pop();writer.WriteFullEndElement();break;}case XmlNodeType.XmlDeclaration:{writer.WriteStartDocument();break;}}switch (skipMode){case 1:{reader.Skip();pathStack.Pop();readResult = !reader.EOF;break;}case 2:{pathStack.Pop();readResult = !reader.EOF;break;}default:{readResult = reader.Read();break;}}}}finally{writer.Close();targetStream.Close();targetStream.Dispose();reader.Close();sourceStream.Close();sourceStream.Dispose();}
}private static bool CompareNodePath(Stack<string> currentNodePathStack, string compareNodePathString)
{var currentArray = currentNodePathStack.Reverse().ToArray();var compareArray = compareNodePathString.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);if (compareArray.Length != currentArray.Length){return false;}bool isDifferent = false;for (int i = 0; i < currentArray.Length; i++){if (compareArray[i] != currentArray[i]){isDifferent = true;break;}}return !isDifferent;
}

转载于:https://www.cnblogs.com/Rabbitism/p/7161926.html

关于大XML文件与大节点处理(System.Xml.XmlTextReader)相关推荐

  1. 【Groovy】Xml 反序列化 ( 使用 XmlParser 解析 Xml 文件 | 获取 Xml 文件中的节点和属性 | 获取 Xml 文件中的节点属性 )

    文章目录 一.创建 XmlParser 解析器 二.获取 Xml 文件中的节点 三.获取 Xml 文件中的节点属性 四.完整代码示例 一.创建 XmlParser 解析器 创建 XmlParser 解 ...

  2. python解析xml文件选用模块_python语言解析xml文件的常用的有两种方式

    MiniDom方式解析xml xml文件以data.xml为例,具体操作如下: data.xml: 保存用户的信息 Jordy 12345678 20 男 上网 功夫 34443678 18 男 功夫 ...

  3. 使用XML文件方式配置log4cxx(log4cxx xml例子)

    废话不多说,直接给出log.xml文件的全部内容. xml例子)" name=image_operate_59151337264079188 alt="使用XML文件方式配置log ...

  4. Castor 解析xml文件报错org.exolab.castor.xml.MarshalException

    Castor 解析xml文件报错org.exolab.castor.xml.MarshalException: Illegal Text data found as child of org.exol ...

  5. php读写xml文件,另辟蹊径 搞定PHP读取XML大文件 数据导入

    由于工作原因,不得不与一个二逼团队合作, 我说直接导出SQL文件给我就好了,而他们坚持要导出XML文件. 或者他们有他们的原因吧,但我还是要叫他们二逼团队,懒得了解他们有什么苦衷. 我想MySQL应该 ...

  6. c# xml文件新增同级节点_[C#.NET 拾遗补漏]08:强大的LINQ

    大家好,这是 [C#.NET 拾遗补漏] 系列的第 08 篇文章,今天讲 C# 强大的 LINQ 查询.LINQ 是我最喜欢的 C# 语言特性之一. LINQ 是 Language INtegrate ...

  7. python对修改图片尺寸后的labelimg2/rolabelimg生成的XML文件进行多级节点的读取/修改/保存

    已经做了四张图片的标注,很复杂,但遇到两个问题: labelimg2无法对边界处的目标进行标注,导致标注不完全: 后续的算法是基于正方形的图片进行训练的,虽然可以训练矩形,但要多一步,不如在标注前就处 ...

  8. tinyxml 读取文本节点_【C++】【TinyXml】xml文件的读写功能使用——写xml文件

    TinyXml工具是常用比较简单的C++中xml读写的工具 需要加载 #include "TinyXml\tinyxml.h" 在TinyXML中,根据XML的各种元素来定义了一些 ...

  9. 打开pdf文件提示文件过大_pdf文件太大如何用pdf转换工具进行压缩?

    PDF文件如果是由许多高清图片组合而成的,一般来说所占的空间都会比较大,这样的话我们在传输文件的时候时间会很长不太方便.那我们可以将PDF文件进行压缩变小这样可以大大提高我们的工作效率.那PDF文件过 ...

最新文章

  1. 科大讯飞2019年创下历史最佳业绩,员工涨薪27%,营收来源妥妥「安徽之光」
  2. 02 判断某个字符串是否由一个子字符串重复组成
  3. java 分页查询_java开发之分页查询
  4. J-Link 输出供电问题
  5. java多线程 - 线程通信
  6. 鼎微方案导航一体机刷机包_SMB方案之星 | 海康威视人脸门禁一体机产品应用方案集锦...
  7. 博弈论 从懵逼到入门 详解
  8. 【转】putty基本操作--不错
  9. Android入门笔记01
  10. 如何让网站自动识别手机端与PC端
  11. python写彩票程序30选7_python实现彩票系统
  12. 智能门锁的千亿市场,为何迟迟不来?
  13. omnigraffle所有模板免费下载网站
  14. 电脑ATX电源接口定义详解
  15. SVN和Git优劣对比
  16. HDUOJ 6555 The Fool
  17. html心碎粒子特效,system-data.html
  18. 苹果Mac OS X 系统下屏幕截图快捷键
  19. 1.5.33 计算分数加减表达式的值
  20. 【架构分析】Weston Inside - 基础数据结构详解

热门文章

  1. [系统开发] Postfix 邮件管理系统
  2. inittab 文件分析
  3. 安装docker后遇到permision问题
  4. centos6.9安装oracle10,2018-10-09 centos6.9 安装cx_Oracle
  5. 百度指数常见php框架,怎么导出数据到excel表格-如何将百度指数数据导出到Excel表格...
  6. nas挂载windows_在windows2012上挂载NAS文件系统
  7. java判断是否为数组_JS如何判断是否是数组?
  8. freescale imx6 编译 linux ltib,TQIMX6Q技术分享——LTIB安装配置(转)
  9. vb科学计算机x y,vb程序用vb实现系统的计算器功能1/x,sqrt,%,+/-, 爱问知识人
  10. 关于MySQLdb连接数据的使用(插入数据,删除数据,更新数据,搜索数据——前端页面完成这些对数据库的操作)