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

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

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

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

示例中提到使用方法是:

while( != reader.ReadChars(buffer, , ))
{
// 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 && != reader.ReadChars(buffer, , ))
{
// 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 - ])
.ToList();
var bigNodeNameList = bigNodePathList.Select(
bigNodePath => bigNodePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries))
.Select(nodePathParts => nodePathParts[nodePathParts.Length - ])
.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 = ;
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 = ;
}
}
else if (bigNodeNameList.Contains(reader.LocalName))
{
var index = bigNodeNameList.IndexOf(reader.LocalName);
if (CompareNodePath(pathStack, bigNodePathList[index]))
{
reader.MoveToContent();
var buffer = new char[];
int len;
while (reader.LocalName == bigNodePathList[index] &&
(len = reader.ReadChars(buffer, , buffer.Length)) > )
{
writer.WriteRaw(buffer, , len);
}
writer.WriteFullEndElement();
skipMode = ;
}
}
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 :
{
reader.Skip();
pathStack.Pop();
readResult = !reader.EOF;
break;
}
case :
{
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 = ; i < currentArray.Length; i++)
{
if (compareArray[i] != currentArray[i])
{
isDifferent = true;
break;
}
}
return !isDifferent;
}

关于大XML文件与大节点处理(System.Xml.XmlTextReader)的更多相关文章

  1. xml文件的根节点layout_width或者layout_height设置无效果的原因分析

    在android开发中相信大家对ListView.GridView等组建都非常熟悉,在使用它们的时候须要自己配置相关的Adapter,而且配置现骨干的xml文件作为ListView等组建的子View, ...

  2. C#中操作xml文件(插入节点、修改、删除)

    已知有一个xml文件(bookstore.xml)如下: <?xml version="1.0" encoding="gb2312"?> <b ...

  3. C#程序中:如何删除xml文件中的节点、元素。

    C#中动态的清理xml文件中的垃圾信息是程序员必会的哦.这就像数据库一样,不会清理数据怎么可以呢?其实xml文件就可以用作一个小的数据库,存储一些简单的信息.所以,用C#程序实现xml文件的增.删.改 ...

  4. C#程序中:如何修改xml文件中的节点(数据)

    要想在web等程序中实现动态的数据内容给新(如网页中的Flash),不会更新xml文件中的节点(数据)是远远不够的,今天在这里说一个简单的xml文件的更新,方法比较基础,很适合初学者看的,保证一看就懂 ...

  5. testng.xml文件结构组成及节点属性说明

    TestNG的DTD检查文件:http://testng.org/testng-1.0.dtd.PHP 更多testng配置及说明,请移步http://testdoc.org/docmaster?pi ...

  6. 节点文件将两个不同格式的XML文件,进行节点对照,并生成一个用于对照功能的XML

    本文纯属个人见解,是对前面学习的总结,如有描述不正确的地方还请高手指正~ 经常有的需求是,需要将一种格式的XML转换成另一种XML.如果要实现这个功能首先需要将两个不同XML手动建立节点对比关系.然后 ...

  7. 使用jdom操作xml文件 去除子节点带有命名空间

    package com.soft.common; import java.util.HashMap; import java.util.Map; import org.jdom2.Namespace; ...

  8. C#程序中:如何向xml文件中插入节点(数据)

    向xml文件中动态的添加节点(数据)是一件很爽的事,可以给你的程序带来很多的方便,比如在web中,如果你的Flash用到了xml文件,这个方法可以让你在后台就轻轻松松的更新你的Flash内容哦!一起研 ...

  9. 读取XML文件的指定节点的值 并转换为Item

    cmb_State_Send.ItemsSource = null; XmlDocument doc = new XmlDocument(); doc.Load("D:\\模板\\Works ...

随机推荐

  1. 中国移动MySQL数据库优化最佳实践

    原创 2016-08-12 章颖 DBAplus社群 本文根据DBAplus社群第69期线上分享整理而成,文末还有书送哦~ 讲师介绍章颖 数据研发工程师 现任中国移动杭州研发中心数据研发工程师,擅长M ...

  2. alexanderanokhin ---DTRACE

    https://alexanderanokhin.wordpress.com/2011/11/13/dynamic-tracing-of-oracle-logical-io/

  3. MVC.NET:提供对字体文件.woff的访问

    在我们的项目中如果使用到了Bootstrap框架的话,通常都必须要支持对其自带的glyphicons-halflings-regular的font文件的访问. 诸如在MVC.NET中,如果一开始什么设 ...

  4. MapReduce编程实战之“高级特性”

    本篇介绍MapReduce的一些高级特性,如计数器.数据集的排序和连接.计数器是一种收集作业统计信息的有效手段.排序是MapReduce的核心技术,MapReduce也可以运行大型数据集间的" ...

  5. 哈理工2015暑假集训 zoj 2975 Kinds of Fuwas

    G - Kinds of Fuwas Time Limit:2000MS    Memory Limit:65536KB    64bit IO Format:%lld & %llu Subm ...

  6. UVA LIVE 7146 Defeat the Enemy

    这个题跟codeforces 556 D Case of Fugitive思路一样 关于codeforces 556 D Case of Fugitive的做法的链接http://blog.csdn. ...

  7. 【数据结构】链式向前星知识点&代码

    代码: struct NODE{ int to; int nxt; int c; }node[MM];//链式向前星 ; void add(int a,int b,int c){ node[lcnt] ...

  8. rk3288对于parameter参数文件的解析处理【转】

    本文转载自:http://blog.csdn.net/groundhappy/article/details/56479694 rk3288有一个parameter文件. 类似于 FIRMWARE_V ...

  9. C++顺序表(模板总结)

    C++顺序表(模板总结) 总结: 1.模板类的实质是什么:让程序员写出和类型无关的代码 2.模板的对象时什么:方法或者类 3.是对类中的一系列操作,提供一个不固定数据类型的方法 用模板做的类的时候要指 ...

  10. c++ string 解析ip

    比如输入是192.168.80.12-15,解析成192.168.80.12.192.168.80.13.192.168.80.14.192.168.80.15. #include <iostr ...