发现VB6中SAX的乐趣
http://www.techng.com/content.aspx?titleid=5748

微软公司的XML核服务(Core Services),也就是广为人知的MSXML2,为VB和COM开发者提供了一种很有用的XML工具箱。在前面的几篇文章中,我已经介绍了MSXML2的DOM解析器,并演示了如何在一个图书目录管理应用程序中使用它的例子。现在,我将带你看看XML解析器coin的SAX部分。

SAX是什么?

受篇幅所限,我只能在本文简单的讨论一下SAX是如何工作的,如果你对SAX感兴趣,我建议你看看我们以前的一篇文章《XML基础教程:掌握SAX 》一文。简单的说,SAX(XML的简单API,即Simple API for XML)是一种连续的push解析器,SAX解析器把XML文档中的元素按照先后顺序依次推到它的主应用程序中。SAX最初是用来作为Java的解析器的,随后用于各种各样的其它语言,包括微软公司的COM实现。最为一种解析器,SAX相对于DOM的一个优势就是处理大文档以及查询文档中某段特定信息。当然,SAX要比DOM复杂,它要求你跟踪SAX正在处理的内容信息以便知道解析器处于文档中的哪个部分。

微软的SAX实现
在MSMAX2中实际上有两种SAX实现,一种实现是为VB程序员提供的,而另一种适合于C++开发者。从VB的角度来看,你需要管理几个类并用SAX运行它们。

SAXXMLReader:解析器本身
MSXML为VB提供的SAX解析器由IVBSAXXMLReader界面定义。SAXXMLReader类是该界面的一个与版本无关(version-independent)的实现,你可以在应用程序中把它做为读取器(reader)来使用,这样可以保证应用程序与MSXML的新版本兼容。你可以通过调用parse或者parseURL方法来设置解析器处理某个文档。就它本身而言,SAXXMLReader只能解析文档,它不能通知你它正在分析的内容。你将需要实现一种有效的界面来实际利用解析器。

内容处理器
IVBSAXContentHandler界面包含了一系列方法, SAX解析器通过调用这些方法就可以向应用程序通知文档中的内容。我在表A中列出了若干个比较重要的方法:
表A

startDocument 当解析器开始解析文档时调用。
startElement 解析器每遇到一个新的元素时(解析器读到元素的开始标记)就调用它。输入参数代表元素的位置以及元素的full-qualified名称。注意SAX使用的是一种深度优先的遍历方法——先解析子元素然后分析同级元素(兄弟节点)。
characters 当数据元素调用startElement方法后调用。该数据作为输入参数传递到本方法。由于SAX解析器的VB实现是非验证性的(non-validating),所以本方法也可以接收白空格。
endElement 调用startElement和characters之后,当解析器读到元素的结束标志时调用。
processingInstruction 当解析器遇到处理指令元素时调用。指令的内容通过一个输入参数传递到这个方法中。
endDocument 当解析器解析文档完毕时调用。也就是说,现在解析器可以解析另一个文档了。

重要的文档处理方法

你至少需要完成界面函数中的startElement和characters方法,并把实现类的一个实例通过它的contentHandler属性传递给SAXXMLReader。

实现内容函数的一个好笑的方面就是SAX是无态的(stateless),也就是说你的实现类必须跟踪当前正在解析的元素(保存你从startElement方法得到的元素名),这样你才可以知道如怎样characters方法来处理接收到的元素内容。还有,目前SAX的VB实现是非验证性的,这就产生了一个有趣的效果:文档中的白空格(white space)实际上是被characters方法处理,而不是像你可能猜测的那样传递给方法ignorableWhitespace。

对错误的处理
SAX解析器使用另一种特殊的界面,即IVBSAXErrorHandler,来向应用程序通知解析错误。尽管在文档中可以引用error和fatalError方法,但当前SAX的VB实现只能调用fatalError。有趣的是解析器同样也向应用程序发送它遇到的错误,这就使得错误处理器(handler)对象有些多余。如果你选择使用其中的某一个,那么你至少要实现fatalError方法并通过使用errorHandler属性来向SAXXMLReader传递一个实现类的实例。

重看“书籍目录”应用程序

现在,让我们把这些部件组装到一个例子中。我已经用SAX取代DOM重写了我们的老朋友——“书籍目录”应用程序。该应用程序得到了相当的简化(我以及删除了添加新书籍以及编辑书籍的功能),这样你就可以集中注意力看看SAX如何工作的。你可以在这儿下载本项目的源代码,它包括了catalog.xml的一份拷贝,该应用程序解析并显示出一个树型视图控件。图A是该它运行时的情形。

图A

运行中的SAX例子程序
创建SAX客户端应用程序的第一步就是实现它的内容处理器界面,即IVBSAXContentHandler。在清单A中,我给出了cSaxReader的代码,它同时实现了内容处理器界面和错误处理器界面。

先让我们谈谈内容处理器界面。你可以看到我是如何实现 startDocument、startElement、characters、和 endElement方法的。StartDocument方法的任务很简单,就是在SAX开始解析一个新的文档时分配集合(collection)类。实际工作是在 startElement和characters方法中完成的。前者保存当前元素的名字,即strLocalName,到一个模块层次上的变量,这样稍后当characters处理元素中的数据时,它可以把数据赋值给适当的book类属性中。当startElement处理一个名字为“book”的元素时,它可以通过oAttributes(一个IVBSAXAttributes实例)参数访问到的id属性来查询该书的id号。最后,当调用endElement时,它抛弃当前元素的名字,并设置一个布尔型的标志变量来表示是否可以结束解析该书。这就避免了characters没有必要的处理两个元素之前的白空格。

正如我在前面所提到的那样,由于严重的(fatal)错误可以作为可捕获的(trapable)错误返回到客户应用程序,因此实现错误处理对象显得有些多余。在实现错误处理器时你可以做的一件事就是判断错误发生在文档中的位置。你可以通过检测IVBSAXLocator实例的lineNumber和columnNumber属性来实现上述功能,IVBSAXLocator实例是错误处理器中fatalError方法的一个参数。

当建立内容处理器和错误处理器后,你接下来只需要通过调用SAXXMLReader的parse或者parseURL方法来设置解析器到工作文档上。

Listing A – cSaxReader.cls

Option Explicit

'implement the content handler and error handler interfaces here
Implements MSXML2.IVBSAXContentHandler
Implements MSXML2.IVBSAXErrorHandler

Private m_book As cBook 'New book
Private m_colBooks As cBooksCollection 'books collection
Private m_oSaxReader As MSXML2.SAXXMLReader 'SAX reader
Private m_currentElement As String 'last element name handed off from reader
Private m_blParsingABook As Boolean 'true if we're inside a book element

Public Sub LoadBooks(strFile As String)
On Error GoTo err_LoadBooks
'SAXXMLReader throws errors for parse errors regardless of whether or not
'we're handling errors in an IVBSAXErrorHandler implementation

'parse a file from a URL
m_oSaxReader.parseURL strFile
Exit Sub

err_LoadBooks:
MsgBox "Unable to load from file, book list may be incomplete."
Exit Sub

End Sub

Public Function GetBookList() As cBooksCollection
'retrieve the finished book list
Set GetBookList = m_colBooks
End Function

Private Sub Class_Initialize()
'set up the SAX reader
Set m_oSaxReader = New MSXML2.SAXXMLReader
'pass a reference to this object to use as the content handler...
Set m_oSaxReader.contentHandler = Me
'and error handler objects
Set m_oSaxReader.errorHandler = Me

End Sub

Private Sub Class_Terminate()
Set m_oSaxReader = Nothing
Set m_colBooks = Nothing
Set m_book = Nothing

End Sub

Private Sub IVBSAXContentHandler_characters(strChars As String)
'skip the element if we aren't parsing a book (inside a book element)
'easy way to skip whitespace
If m_blParsingABook Then
'check the last element name sent to startElement to determine
'what to do with the data we just received
Select Case m_currentElement
Case "title"
m_book.Title = strChars
Case "author"
m_book.Author = strChars
Case "price"
m_book.Price = CCur(strChars)
Case "publish_date"
m_book.Pub_Date = CDate(strChars)
Case "genre"
m_book.Genre = strChars
Case "description"
m_book.Description = strChars
End Select
End If

End Sub

Private Property Set IVBSAXContentHandler_documentLocator(ByVal RHS As MSXML2.IVBSAXLocator)

End Property

Private Sub IVBSAXContentHandler_endDocument()

End Sub

Private Sub IVBSAXContentHandler_endElement(strNamespaceURI As String, strLocalName As String, strQName As String)
'if we just moved out of a book element, then create a new Book
'object and reset the parsing flag.
If strLocalName = "book" Then
m_colBooks.AddBook m_book
m_blParsingABook = False
End If
'discard the current element name
m_currentElement = ""

End Sub

Private Sub IVBSAXContentHandler_endPrefixMapping(strPrefix As String)

End Sub

Private Sub IVBSAXContentHandler_ignorableWhitespace(strChars As String)

End Sub

Private Sub IVBSAXContentHandler_processingInstruction(strTarget As String, strData As String)

End Sub

Private Sub IVBSAXContentHandler_skippedEntity(strName As String)

End Sub

Private Sub IVBSAXContentHandler_startDocument()
'create a new collection to hold the contents of a new document
Set m_colBooks = New cBooksCollection

End Sub

Private Sub IVBSAXContentHandler_startElement(strNamespaceURI As String, strLocalName As String, strQName As String, ByVal oAttributes As MSXML2.IVBSAXAttributes)
'preserve the name of the element we just entered
m_currentElement = strLocalName

'if this element is a book element then create a new book object
'and set it's ID property, then set the parsing flag so that the
'characters method will handle the child nodes of this book
If strLocalName = "book" Then
Set m_book = New cBook
m_book.ID = oAttributes.getValueFromName("", "id")
m_blParsingABook = True
End If

End Sub

Private Sub IVBSAXContentHandler_startPrefixMapping(strPrefix As String, strURI As String)

End Sub

Private Sub IVBSAXErrorHandler_error(ByVal oLocator As MSXML2.IVBSAXLocator, strErrorMessage As String, ByVal nErrorCode As Long)

End Sub

Private Sub IVBSAXErrorHandler_fatalError(ByVal oLocator As MSXML2.IVBSAXLocator, strErrorMessage As String, ByVal nErrorCode As Long)
'a fatal error occurred, note that the reader will also raise an error after this
'routine exits
Dim strMsg As String
'The oLocator object contains context information
'such as line and column numbers for the error
strMsg = strErrorMessage & vbCrLf & "Line: " & oLocator.lineNumber & " Column: " & oLocator.columnNumber
MsgBox "Parse failed: " & strMsg
End Sub

Private Sub IVBSAXErrorHandler_ignorableWarning(ByVal oLocator As MSXML2.IVBSAXLocator, strErrorMessage As String, ByVal nErrorCode As Long)

End Sub

有关资料:下载本项目的源代码

转载于:https://www.cnblogs.com/vboy/articles/160756.html

发现VB6中SAX的乐趣[转]相关推荐

  1. Linux C/C++ 编程 内存管理之道:探寻编程世界中的思维乐趣

    内存管理之道:探寻编程世界中的思维乐趣 引言(Introduction) 内存分配区域(Memory Allocation Regions) 内存分配与转移(Memory Allocation and ...

  2. 如何发现数据中的异常值?对异常值是怎么处理的?

    如何发现数据中的异常值?对异常值是怎么处理的? 如何发现数据中的异常值?对异常值是怎么处理的? 一种是基于统计的异常点检测算法例如极差,四分位数间距,均差,标准差等,这种方法适合于挖掘单变量的数值型数 ...

  3. Python代码发现链表中的环并输出环中的第一个元素

    Python代码发现链表中的环并输出环中的第一个元素 # Python代码发现链表中的环并输出环中的第一个元素 # Find first node of loop in a linked list # ...

  4. 以人为本的机器学习:谷歌人工智能产品设计概述 By 机器之心2017年7月17日 12:13 取代了手动编程,机器学习(ML)是一种帮助计算机发现数据中的模式和关系的科学。对于创建个人的和动态的经历

    以人为本的机器学习:谷歌人工智能产品设计概述 By 机器之心2017年7月17日 12:13 取代了手动编程,机器学习(ML)是一种帮助计算机发现数据中的模式和关系的科学.对于创建个人的和动态的经历来 ...

  5. 如何发现 Kubernetes 中服务和工作负载的异常

    大家好,我是来自阿里云的李煌东,今天由我为大家分享 Kubernetes 监控公开课的第二节内容:如何发现 Kubernetes 中服务和工作负载的异常. 本次分享由三个部分组成: 一.Kuberne ...

  6. vb6中使text控件的光标随着增加的内容向下移动

    vb6中使text控件的光标随着增加的内容向下移动 Dim i As Integer Private Sub Command1_Click() Text1.Text = Text1.Text + &q ...

  7. VB6中如何使用C#开发的WebService进行开发

    VB6中如何使用C#开发的WebService进行开发<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office ...

  8. session中存放一个对象,只修改对象的属性,不将修改后的对象存放session,发现session中存放的对象也发生改变!

    标题简单描述:先将一个对象放入session,只对对象属性值进行修改,但不将修改后的对象存放session中,发现session中存放的对象属性值也相对应的改变. Person person=new ...

  9. 程序编号以后计算机能够查出,华威大学研究人员开发出计算机程序,可发现量子计算机中的“泄漏”...

    原标题:华威大学研究人员开发出计算机程序,可发现量子计算机中的"泄漏" 当量子计算机中的信息进入不理想的状态时,如果有一种计算机程序能够及时发现这种"泄漏",便 ...

最新文章

  1. error 图片,加载错误-》实用笔记
  2. 云服务器怎么拷贝和删除文件,怎样给云服务器拷贝文件
  3. 收藏一下mybatis全局参数配置
  4. RHEL6 让 root可以登录桌面
  5. 三目运算符对比三个_Javascript之if条件语句和三目运算符
  6. P4309-[TJOI2013]最长上升子序列【Splay】
  7. 使用 OpenCL.Net 进行 C# GPU 并行编程
  8. c 文件操作_你电脑用久了,会有多少重复文件?快用它来整理一下吧
  9. mysql查看线程详解(转载)
  10. java 线程 寄存器 地址_Java高级进阶多线程学习之路(四)CPU与内存
  11. 迅捷PDF编辑器如何编辑PDF文字图文教程
  12. python 正数变成负数_Python基础之位运算符(含原码反码补码的通俗解释)
  13. 150. Evaluate Reverse Polish Notation逆波兰表达式
  14. 塔夫斯大学计算机教授,塔夫茨大学开发出一系列3D打印半球形超材料 具有独特微波或光学特性...
  15. 商业智能BI能做什么
  16. Kaggle Top1% 是如何炼成的!
  17. CMMI V2.0培训纪实
  18. 用计算机怎么打出X,x的平方怎么在电脑上打出来(常见数学符号打法
  19. Pause Giant AI Experiments: An Open Letter(暂停大型人工智能实验: 一封公开信)
  20. 缓冲区溢出之栈溢出利用(手动编写无 payload 的 Exploit)

热门文章

  1. 企业要做有价值的私域流量三大关键
  2. getMap(Thread t)
  3. 为什么部分Android用户不喜欢用iOS系统?
  4. Qt——P10 自定义的信号和槽
  5. 算法--最大连续子序列和(动态规划,分而治之)
  6. 读取SQL Server事务日志
  7. azure db 设置时区_使用Azure Cosmos DB开始您的旅程
  8. SQL解析和优化器获得重大思路进展
  9. Asp.Net MVC 自定义登录过滤器
  10. linux进程的创建、执行和消亡