博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于大XML文件与大节点处理(System.Xml.XmlTextReader)
阅读量:5731 次
发布时间:2019-06-18

本文共 5167 字,大约阅读时间需要 17 分钟。

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

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

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

方法说明:

示例中提到使用方法是:

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

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

Value
Value

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

Value
Value

比如这个画风的,用示例代码去读第一个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
processNodePathList = new List
{
"/Root/Path/to/Target"};List
bigNodePathList = new List
{ "/Root/Path/to/Big/Node" }; private static void ProcessBigXmlFile(string sourcePath, string targetPath, IList
processNodePathList, IList
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
(); 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("", 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
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

你可能感兴趣的文章
【洛天依】几首歌的翻唱(无伴奏)
查看>>
strcspn
查看>>
OpenSSL初瞻及本系列的博文的缘由
查看>>
ISO8583接口的详细资料
查看>>
tmux不自动加载配置文件.tmux.conf
查看>>
经验分享:JavaScript小技巧
查看>>
[MOSEK] Stupid things when using mosek
查看>>
程序实例---栈的顺序实现和链式实现
查看>>
服务的使用
查看>>
Oracle 用户与模式
查看>>
网站开发流程以及HTML5简介(八)
查看>>
MairDB 初始数据库与表 (二)
查看>>
RabbitMQ】三种Exchange模式——订阅、路由、通配符模式
查看>>
连接数据库——java
查看>>
拥在怀里
查看>>
chm文件打开,有目录无内容
查看>>
whereis、find、which、locate的区别
查看>>
TRUNK
查看>>
一点不懂到小白的linux系统运维经历分享
查看>>
MDT 2013 从入门到精通之软件自动化部署设置
查看>>