如何在C#中逐步加载XML?

4
我需要在异步回调中逐步处理从ResponseStream加载的XML。答复如下:
  <root>
     <node ...>
        .....
     </node>
     <node />
     ...
  </root>

我需要翻译关于IT技术的内容,具体是关于schema的处理。我需要能够在节点完整到达之前对<node>进行处理。

是否有使用标准.NET解析它的常规方法?

3个回答

3
System.Xml.XmlTextReader 

"表示提供快速、无缓存、单向访问 XML 数据的阅读器。" http://msdn.microsoft.com/en-us/library/system.xml.xmltextreader.aspx "编辑:这是一个快速 hack,但它确实证明了阅读器是懒加载的。"
 public class XmlTextReaderTest
    {
        public void RunTest()
        {
            var fs = new XmlTextReader(new Fs(@"c:\TestXml.xml"));
            while (fs.Read())
                File.AppendAllText(@"c:\xLog.txt", "Processing node..." + Environment.NewLine);
        }
    }

    public class Fs : FileStream
    {
        public Fs(string path)
            : base(path, FileMode.Open)
        {

        }

        public override int Read(byte[] array, int offset, int count)
        {
            File.AppendAllText(@"c:\xLog.txt", "Reading from stream..." + Environment.NewLine);
            var ans = base.Read(array, offset, count);
            return ans;
        }
}

我还没有找到逐步调用它的方法。如果在非完整流上调用,会发出异常。 您能描述一下如何在渐进式加载的上下文中使用它吗? - datacompboy
那么,我应该如何将读取的文本放入MemoryStream中,以允许.Read()在没有新信息时返回false而不是异常?我使用responseStream.BeginRead()读取数据进行处理,并且需要并行处理部分解码的XML。 也许我的问题不太清楚 - 但是实际上,如何将新的数据片段推送到XMLReader? - datacompboy
你能告诉我数据来自哪里吗?如果你是通过自定义过程即时创建数据,那么你可能需要编写一个自定义的Stream或TextReader实现。 - Ani
数据来自对服务器的长轮询调用。 - datacompboy
什么是传输?您当前是否正在使用NetworkStream类? - Ani

1

不要在异步回调上调用它,你不需要这样做(相信我,这会变得更清晰...)。

ResponseStream将在信息可用时加载。对于小流(对于相当大的“小”值,恐怕是这样),如果没有以块发送,则在整个流被下载时就会发生这种情况。但是,如果使用分块传输编码发送流(如果关闭缓冲或调用Response.Flush(),则在ASP.NET中会发生这种情况,其他Web服务器技术也有其等效物),则流将在第一个块处可用。

从GetResponse()返回时从ResponseStream创建XMLReader。它将从第一个可用块开始处理,并且透明地获取随后到达的块,以便您的代码。

确保按照可用的方式处理这些节点实际上有助于沿着线路进一步进行代码。例如,如果要输出到控制台或表单,请在处理每个节点(或一小批节点)时执行此操作,而如果要从这些节点创建对象,则应yield return它们而不是建立集合。

现在,重要的事情显然是网络流是否分块,而不是你的处理代码。如果生产者是另一方,无法说服他们这样做,那么您将需要降低处理级别。但是,如果是这种情况,则这样做很可能是一种虚假优化,因为整个处理将在他们发送第一个字节之前完成,并且这是最大的延迟所在。实际上,如果获取整个响应下载的延迟对您的代码造成问题,则需要让他们开始发送分块,因为即使您采用最有效的方法,延迟仍然太大。

值得一提的是,我最近确认,在使用XmlReader处理分块数据的WebResponse时(其中我控制了客户端和服务器端代码,并且可以在调试器中运行并检查操作顺序),每个块可用时确实进行处理。


那么,如果服务器以一个非常大的流(非分块)发送数据,就没有办法将数据推入XMLReader中吗? 我不想为每个正在处理的下载流创建新线程。使用异步回调是可以的,但如果流太大,处理开始之前会有太大的延迟。 - datacompboy
您可以通过降低WebResponse的级别来实现,但是如果从Web获取的数据是即时生成的,则等待发送请求并接收第一个字节数据之间的时间仍然可能是更大的问题,因此我会极力推荐分块数据(这也会减少服务器上的内存开销)。 - Jon Hanna

0

是的,有一个你可以使用的读取器。基本上沿着流程走,并为其识别的每个元素(元素、属性等)抛出一个事件。


1
除了“是的,你可以这样做”之外,还需要更多的细节吗? - Oded
是的,请描述具体的Reader是哪一个。 我尝试将传入的数据传递给StreamReader,并从中提取到XmlReader,但它会抛出关于不完整XML的异常,而不是允许读取当前准备好的部分。 我知道SAX解析器可以帮助我,但这不是核心.NET。 - datacompboy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接