【发布时间】:2023-03-16 17:32:01
【问题描述】:
考虑以下 XML 文档:
<?xml version="1.0" encoding="iso-8859-1" ?>
<a>
<b>
<c1 description="abc123" />
<c2 description="bbbasdasdbc123" />
<c3 description="cccbasdasdc123" />
</b>
<b>
<c1 description="abc123" />
<c2 description="bbbasdasdbc123" />
<c3 description="cccbasdasdc123" />
<c4 description="abc123"" />
<c5 description="bbbasdasdbc123" />
<c6 description="cccbasdasdc123" />
</b>
<b>
<c1 description="abcaslkjkl123" weight="10" />
</b>
</a>
目前这个 XML 文档是无效的,在 Firefox 中它指向有问题的行:Line 12 col 27... 即额外的双引号。 双引号不是这里的问题。错误的原因可能是导致 XML 文档无效的任何原因。
关键是当我尝试加载 XML 文档时会发生错误 - 我从中知道行号和列... - 之后我别无选择,只能将文件标记为 errored-do-something-以后再说吧。
我想做的是删除封装违规行的<b> 节点(或将其提取以供以后进一步的错误处理)
即删除
<b>
<c1 description="abc123" />
<c2 description="bbbasdasdbc123" />
<c3 description="cccbasdasdc123" />
<c4 description="abc123"" />
<c5 description="bbbasdasdbc123" />
<c6 description="cccbasdasdc123" />
</b>
离开
<?xml version="1.0" encoding="iso-8859-1" ?>
<a>
<b>
<c1 description="abc123" />
<c2 description="bbbasdasdbc123" />
<c3 description="cccbasdasdc123" />
</b>
<b>
<c1 description="abcaslkjkl123" weight="10" />
</b>
</a>
XML 可以很大
我已经调查了这些最终导致我使用 File.ReadLines(sourceXMLFile).Take(...) 等
How to read a text file reversely with iterator in C#
Get last 10 lines of very large text file > 10GB
https://msdn.microsoft.com/en-us/library/w5aahf2a%28v=vs.110%29.aspx
并且事先使用模式来验证 XML 不是一种选择 (http://www.codeguru.com/csharp/csharp/cs_data/xml/article.php/c6737/Validation-of-XML-with-XSD.htm)。
在知道有问题的行号后,我已经考虑过尝试解决这个问题的方法,并想出了这个:
public void ProcessXMLFile(string sourceXMLFile, string errorFile)
{
XmlDocument xmlDocument = new XmlDocument();
string outputFile1 = @"c:\temp\f1.txt";
string outputFile2 = @"c:\temp\f2.txt";
string soughtOpeningNode = "<b>";
string soughtClosingNode = "</b>";
string firstPart = "";
string secondPart = "";
int lastNode = 0;
int firstNode = 0;
try
{
xmlDocument.Load(sourceXMLFile);
}
catch (XmlException ex)
{
int offendingLineNumber = ex.LineNumber;
// Create the first part of the file that comprises everything upto and including the line that caused the error
using (StreamWriter f1 = new StreamWriter(outputFile1))
{
firstPart = string.Join("\r\n", File.ReadLines(sourceXMLFile).Take(offendingLineNumber));
f1.WriteLine(firstPart);
lastNode = firstPart.LastIndexOf(soughtOpeningNode);
}
// Create the file that contains the remainder of the original file starting after the line number that caused the error
using (StreamWriter f2 = new StreamWriter(outputFile2))
{
secondPart = string.Join("\r\n", File.ReadLines(sourceXMLFile).Skip(offendingLineNumber));
f2.WriteLine(secondPart);
firstNode = secondPart.IndexOf(soughtClosingNode);
}
// Create the XML file without the node whose child caused the error...
using (StreamWriter d1 = new StreamWriter(sourceXMLFile))
{
d1.WriteLine(firstPart.Substring(0, lastNode));
d1.WriteLine(secondPart.Substring(firstNode + soughtOpeningNode.Length + 1));
}
// Write the node that contained the offending line number for later processing
using (StreamWriter d1 = new StreamWriter(errorFile, true))
{
d1.WriteLine(firstPart.Substring(lastNode));
d1.WriteLine(secondPart.Substring(0, firstNode + soughtClosingNode.Length + 1));
}
File.Delete(outputFile1);
File.Delete(outputFile2);
ProcessXMLFile(sourceXMLFile, errorFile);
}
}
然后开始:
ProcessXMLFile(@"c:\temp\myBigFile.xml", @"c:\temp\myBigFile-errors.txt");
那么我的问题:
- 这可行,但有更好的方法吗?
- 在处理包含许多错误的 XML 文件 (c70Mb) 时,它最终会耗尽内存(任务管理器显示内存使用率在 16Gb m/c 上一直攀升至 99%)。
- 即使我强制例程完成内存仍保持在 99% 并且仅在 VS2010 停止时下降,那么如何才能提高内存使用效率?
指针将不胜感激。
赛。
【问题讨论】:
-
使用 StreamReader 之类的流类和 ReadLine() 方法来获取需要编辑的行。
-
嗨@jdweng。这不会做我所追求的,即如何切出包含违规行的节点。
-
您需要打开第二个流以保存更改的结果。
-
嗨,是的,刚刚发现那里的逻辑错误。我试图成为一个聪明的亚历克。将发布适用于原始文件的新代码(原始文件会变小,而结果会变大)。很抱歉打扰您。
标签: c# xml validation memory-management