关于大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 ...
随机推荐
- Colored Sticks (并查集+Trie + 欧拉路)
Time Limit: 5000MS Memory Limit: 128000K Total Submissions: 37340 Accepted: 9796 Description You ...
- N天学习一个linux命令之vmstat
用途 查看系统资源整体使用情况,包括进程数量,CPU,内存,IO,swap等资源统计信息 用法 vmstat [options] [delay [ count]] 常用选项 -a 显示active/i ...
- 通过urllib2抓取网页内容(1)
一.urllib2发送请求 import urllib2 url = 'http://www.baidu.com' req = urllib2.Request(url) response = urll ...
- 零基础学python-4.2 其它内建类型
这一章节我们来聊聊其它内建类型 1.类型type 在python2.2的时候,type是通过字符串实现的,再后来才把类型和类统一 我们再次使用上一章节的图片来说明一些问题 我们通过对照上面的图片.在p ...
- oc35--自定义构造方法
// // Person.h #import <Foundation/Foundation.h> @interface Person : NSObject @property int ag ...
- Head First 设计模式 —— 策略设计模式
创建一个能够根据所传递的参数对象的不同而具有不同行为(动态绑定的多态机制)的方法,被称为策略设计模式.
- bzoj1699
st表 我还不会st表 f[i][j]表示[i,i+2^j)区间的最值 构造就像lca一样f[i][j]=f[i][j-1] f[i][j]=max(f[i][j-1],f[i+(1<<( ...
- mybatis的二级缓存
在mybatis主配置文件里configuration标签里添加 <settings> <setting name="cacheEnabled" value=&q ...
- SqlMap常用参数(一)
sqlmap可谓是利用sql注入的神器了,sqlmap的参数很多,接下介绍几种常见的参数. 一.注入access数据库常用的参数 sqlmap.py -u "url" //判断参 ...
- 工具分享1:文本编辑器EditPlus、汇编编译器masm、Dos盒子
工具已打包好,需要即下载 链接 https://pan.baidu.com/s/1dvMyvW 密码 mic4