关于大XML文件与大节点处理(System.Xml.XmlTextReader)
近期有个任务要求处理大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)的更多相关文章
- xml文件的根节点layout_width或者layout_height设置无效果的原因分析
在android开发中相信大家对ListView.GridView等组建都非常熟悉,在使用它们的时候须要自己配置相关的Adapter,而且配置现骨干的xml文件作为ListView等组建的子View, ...
- C#中操作xml文件(插入节点、修改、删除)
已知有一个xml文件(bookstore.xml)如下: <?xml version="1.0" encoding="gb2312"?> <b ...
- C#程序中:如何删除xml文件中的节点、元素。
C#中动态的清理xml文件中的垃圾信息是程序员必会的哦.这就像数据库一样,不会清理数据怎么可以呢?其实xml文件就可以用作一个小的数据库,存储一些简单的信息.所以,用C#程序实现xml文件的增.删.改 ...
- C#程序中:如何修改xml文件中的节点(数据)
要想在web等程序中实现动态的数据内容给新(如网页中的Flash),不会更新xml文件中的节点(数据)是远远不够的,今天在这里说一个简单的xml文件的更新,方法比较基础,很适合初学者看的,保证一看就懂 ...
- testng.xml文件结构组成及节点属性说明
TestNG的DTD检查文件:http://testng.org/testng-1.0.dtd.PHP 更多testng配置及说明,请移步http://testdoc.org/docmaster?pi ...
- 节点文件将两个不同格式的XML文件,进行节点对照,并生成一个用于对照功能的XML
本文纯属个人见解,是对前面学习的总结,如有描述不正确的地方还请高手指正~ 经常有的需求是,需要将一种格式的XML转换成另一种XML.如果要实现这个功能首先需要将两个不同XML手动建立节点对比关系.然后 ...
- 使用jdom操作xml文件 去除子节点带有命名空间
package com.soft.common; import java.util.HashMap; import java.util.Map; import org.jdom2.Namespace; ...
- C#程序中:如何向xml文件中插入节点(数据)
向xml文件中动态的添加节点(数据)是一件很爽的事,可以给你的程序带来很多的方便,比如在web中,如果你的Flash用到了xml文件,这个方法可以让你在后台就轻轻松松的更新你的Flash内容哦!一起研 ...
- 读取XML文件的指定节点的值 并转换为Item
cmb_State_Send.ItemsSource = null; XmlDocument doc = new XmlDocument(); doc.Load("D:\\模板\\Works ...
随机推荐
- 中国移动MySQL数据库优化最佳实践
原创 2016-08-12 章颖 DBAplus社群 本文根据DBAplus社群第69期线上分享整理而成,文末还有书送哦~ 讲师介绍章颖 数据研发工程师 现任中国移动杭州研发中心数据研发工程师,擅长M ...
- alexanderanokhin ---DTRACE
https://alexanderanokhin.wordpress.com/2011/11/13/dynamic-tracing-of-oracle-logical-io/
- MVC.NET:提供对字体文件.woff的访问
在我们的项目中如果使用到了Bootstrap框架的话,通常都必须要支持对其自带的glyphicons-halflings-regular的font文件的访问. 诸如在MVC.NET中,如果一开始什么设 ...
- MapReduce编程实战之“高级特性”
本篇介绍MapReduce的一些高级特性,如计数器.数据集的排序和连接.计数器是一种收集作业统计信息的有效手段.排序是MapReduce的核心技术,MapReduce也可以运行大型数据集间的" ...
- 哈理工2015暑假集训 zoj 2975 Kinds of Fuwas
G - Kinds of Fuwas Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu Subm ...
- UVA LIVE 7146 Defeat the Enemy
这个题跟codeforces 556 D Case of Fugitive思路一样 关于codeforces 556 D Case of Fugitive的做法的链接http://blog.csdn. ...
- 【数据结构】链式向前星知识点&代码
代码: struct NODE{ int to; int nxt; int c; }node[MM];//链式向前星 ; void add(int a,int b,int c){ node[lcnt] ...
- rk3288对于parameter参数文件的解析处理【转】
本文转载自:http://blog.csdn.net/groundhappy/article/details/56479694 rk3288有一个parameter文件. 类似于 FIRMWARE_V ...
- C++顺序表(模板总结)
C++顺序表(模板总结) 总结: 1.模板类的实质是什么:让程序员写出和类型无关的代码 2.模板的对象时什么:方法或者类 3.是对类中的一系列操作,提供一个不固定数据类型的方法 用模板做的类的时候要指 ...
- 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 ...