我在CSDN的第一篇Blog是关于XML,介绍使用MSXML的DOM API来处理XML。当时曾经说后续介绍另一种处理模式SAX,结果一晃过了很多年也没有写。实在是因为SAX模型太过麻烦,也没实际用过。SAX是够麻烦的,连.NET Framework都没有提供类似的API,而改为提供XmlReader/Writer。在非托管环境下,XmlLite提供了类似的XmlReader/Writer接口。
SAX和XmlReader一样,都是关于流式处理XML的。因为使用DOM API必须把整个XML文档首先加载了,这样会占用大量的内存,特别是xml文档很大的时候。那么,我们能不能一边读一边处理呢?这就是SAX和XmlReader要解决的。只是SAX采用Push的模式,而XmlReader采用Pull的模式。在Push的模式下,调用者是被动的等待通知(当前读到了什么位置)。而在Pull模式下,调用者控制着读取进程,当前读到了什么,要不要继续往下读。 在Pull模式下,程序流程更清晰明了。
为了更好的理解,试着使用XmlLite+WinHttp写了一个简单的RSS下载解析测试。
这里遇到的一个难题是,如果读到了不认识的Xml节点,想跳过怎么办?特别是,如果这个节点还包括更多的子节点怎么办?我的解决办法是,递归的读,直到遇到结束节点(EndElement)。具体请参见ReadElementToEnd函数。另外需要创建一个IMultiLanguage2对象,这样XmlLite就可以自动识别和转换GB2312编码的Stream了,因为默认只能处理UTF-8编码的。
XmlReader只能从IStream对象中读取数据,但是WinHttp并不提供这样的接口怎么办?于是自己构造一个IStream对象,只实现IStream的IUnknown接口和Read方法。
这样就搞定了,由XmlReader驱动WinHttp从网络上读取数据,边读边处理,绝不浪费多余的内存和带宽。
参考:
MSDN Magazine介绍XmlLite的文章
http://msdn.microsoft.com/zh-cn/magazine/cc163436.aspx
MSDN文档
http://msdn.microsoft.com/en-us/ms752872.aspx