大型单行XML文件解析:最有效的方法?

时间:2012-03-15 00:00:18

标签: xml xml-parsing

我试图确定解析.svclog文件的最有效方法是什么。为了给你更多的上下文,我处理的.svclog文件看起来像http://msdn.microsoft.com/en-us/library/aa751795.aspx中的内容。跟踪逻辑在.svclog文件中创建<E2ETraceEvent/>个元素,将它们全部放在一行上,因此最终得到10兆字节的单行XML,例如:

<E2ETraceEvent [...]</E2ETraceEvent><E2ETraceEvent [...] </E2ETraceEvent>...

从这条巨线一次读取一个<E2ETraceEvent/>元素的最有效方法是什么?我知道有一些工具可以基本上为你缩进XML,并将更改保存到同一个文件或一个单独的文件中。这是我宁愿跳过的另一个步骤,因为考虑到我可能必须处理的这些文件的数量,性能将非常重要。我甚至不想在开始处理之前缩进一百个胖文件。

我可以将整个文件加载到内存中并将其视为一个字符串(在我的情况下,它们的上限为30兆),但我想要实现某种&#34;对数合并&#34; #34;未来的逻辑,我可能需要将数百个文件拼接在一起,因此一次将它们全部加载到内存中就不会发生。

我可能会使用带有"<E2ETraceEvent.*?</E2ETraceEvent>"的正则表达式并一次前进一个元素(这有效吗?)。 我实际上可以手动实现一次读取一个字符的状态机。这听起来很糟糕:))

很多选择,但我正在寻找真正干净和优雅的东西。

PS。在解析中处理单行文件真的很常见吗?我之前没有完成太多的解析工作,但几乎所有与我合作过的工具似乎都依赖于一次读取 x 的行数。当你在整个文件中没有一个换行符时,所有这一切都变得毫无用处。

2 个答案:

答案 0 :(得分:2)

由于你的基本文件片段而不是普通文件,你可以use the underlying XmlReader classes to process it

// just a test string... XmlTextReader can take a Stream as first argument instead
var elements = @"<E2ETraceEvent/><E2ETraceEvent/>";

using (var reader = new XmlTextReader(elements, XmlNodeType.Element, null))
{
    while (reader.Read())
    {
        Console.WriteLine(reader.Name);
    }
}

这将一次读取一个元素的XML文件,并且不会将整个文档保留在内存中。无论你在读取循环中做什么都是特定于你的用例:)

答案 1 :(得分:2)

如果有人遇到破损痕迹的问题,我就制作了这个PowerShell脚本。

function process-event
{
    $dest = $args[1]
    Get-ChildItem $args[0] | 
        Select-String "([<]E2ETraceEvent.*?(?=[<]E2ETraceEvent))" -AllMatches |
            ForEach-Object { $matches = $_.Matches; 
                foreach ($m in $matches) {  
                    Add-Content -Path $dest -Value $m.Value } };
}

function process-log
{
    '<?xml version="1.0" encoding="utf-8"?><Tracing>' | Out-File $args[1]
    process-event $args[0] $args[1]
    '</Tracing>' | Out-File $args[1] -append
}

process-log .\the_log.svclog .\the_log_fix.svclog

已更新! 这不是很快,我只需要300mb文件,但它会修复它们而不是烧掉所有RAM。