统计

  • 随笔 - 50
  • 文章 - 42
  • 评论 - 147
  • 引用 - 0

留言簿(6)

随笔分类

文章分类

Link

搜索

  •  

积分与排名

  • 积分 - 154428
  • 排名 - 161

最新评论

阅读排行榜

评论排行榜

基于事件解析的SAX模型分析
SAX2解析器读XML文档,然后产生基于特殊符号的事件。SAX2解析器实际上并不为该文档在内存中创建一棵树结构,它序列的处理一个文档的内容并产生相关的事件。

  比如,当你进行基于事件的编程的时候,你可以创建函数来响应用户定义的事件(比如OnClick事件)。在利用SAX进行编程的时候,需要注意的是,是解析器而不是用户产生事件。

  比如考虑下面一个简单的文档。

  <?xml version="1.0"?>
  <parts>
  <part>TurboWidget</part>
  </parts>

  当SAX2在处理这个文档的时候,它产生如下的一系列的事件:

  StartDocument( )
  StartElement( "parts" )
  StartElement( "part" )
  Characters( "TurboWidget" )
  EndElement( "part" )
  EndElement( "parts" )
  EndDocument( )

  可以把SAX2看成是一个有拉特点(PUSH)的解析器,SAX2产生事件,然后你可以自己去处理些事件。实际上,当SAX2在解析一个文档的时候,SAXXMLReader读该文档并产生一系列的事件,你可以选择一些事件进行处理。

  创建一个应用SAX的应用程序框架

  SAX2产生的事件包括如下的种类:

  ¨ 和XML文档内容相关的事件(ISAXContentHandler)

  ¨ 和DTD相关的事件(ISAXDTDHandler)

  ¨ 出现错误时发生的事件(ISAXErrorHandler)

  为了处理这些事件,你需要实现一个相关的处理类,该处理类需要包含一些方法来处理相关的事件。你必须对你想要处理的事件实现相关的处理。如果你不想处理某一个事件的话,只需要简单的忽略它就可以。在实际应用中,我们首先要继承这些接口,用C++我们可以创建一个类,在这个类的方法中,我们可以告诉应用程序在接收到一个事件的时候如何进行处理。下面是建立一个基于SAX的应用的基本步骤:

  1. 创建头文件当使用SAX2的时候,我们需要用到动态连接库MSXML.DLL,为了使用MSXML中包含的SAX2接口,你必须在程序的头文件(一般在stdafx.h中)中包含下列的代码:

  #import raw_interfaces_only


  using namespace MSXML2;

  2. 建立具体的操作(handler)类,SAX2主要定义了三个基本的操作类,它们分别是ISAXContentHandler,ISAXDTDHandler和ISAXErrorHandler。

  ISAXContentHandler是用来处理SAX2解析器对文档内容进行解析时所产生的消息的,ISAXXMLReader通过方法putContentHandler来注册这个实例。而ISAXDTDHandler是用来处理和DTD相关的基本的消息的,ISAXXMLReader通过方法putDTDHandler来注册这个实例。ISAXErrorHandler提供了对在解析过程中遇到错误时产生的错误事件的处理,ISAXXMLReader通过方法putErrorHandler来注册这个实例

  因为这三个类都是用来对事件进行处理的,并且需要在接口ISAXXMLReader中进行注册。但是它们的基本使用方法类似,所以我们这里只详细描述对接口ISAXContentHandler 的操作。

  ISAXContentHandler接口接收关于文档的内容变化的事件,这是实现SAX应用所需要的最重要的接口,如果应用在遇到基本的解析事件的时候需要被通知的话,ISAXXMLReader通过方法putContentHandler来注册这个实例,然后ISAXXMLReader就使用这个实例来报告基于文档的事件,比如元素的开始,元素的结束和相关的字符串数据等等。ISAXContentHandler 包括了很多的方法:比如startDocument,endDocument,startElement,endElement等等。实际上它包含了好接个startXXX和endXXX对来建立不同的信息集合的抽象。比如startDocument方法在文档信息开始的时候被调用,而在startDocument以后被调用的方法就被认为是文档信息项(item)的子项。在文档信息内容结束的时候endDocument就被调用,表示文档信息的结束。 实际上是SAX2在解析文档的时候,当处于文档某一位置的时候,会激发相应的方法,比如当一个文档开始的时候,就会激发startDocument方法,在实际实现的时候,我们可以在我们继承ISAXContentHandler类的实现类中,重载该方法,实现我们自己想要的处理。我们可以把这些方法看成是ISAXContentHandler接口提供给我们的。需要注意的是事件被处理的顺序和信息在文档中的位置是一致的。

  同时需要注意的是,如果我们需要在我们的应用中对这些消息进行处理的话,我们就要继承处理这些消息的类,比如我们只需要对文档内容进行处理,而忽略对DTD和解析过程中错误(Error)的处理,那么我们只需要创建一个新的类,该类继承ISAXContentHandler接口,因为ISAXContentHandler中定义了很多的事件处理方法,而事实上我们只需要对我们所关心事件的处理方法进行重载,对我们不关心的事件可以简单的忽略它。

  比如我们只关心startElement和endElement事件,而且我们假设我们建立的类的名称为CXMLContentDeal,我们的类就可以如下面所示:

  class CXMLContentDeal : public ISAXContentHandler
   {
    public:
     CXMLContentDeal();
     virtual CXMLContentDeal ();
      virtual HRESULT STDMETHODCALLTYPE startElement(
       /* [in] */ wchar_t __RPC_FAR *pwchNamespaceUri,
       /* [in] */ int cchNamespaceUri,
       /* [in] */ wchar_t __RPC_FAR *pwchLocalName,
       /* [in] */ int cchLocalName,
       /* [in] */ wchar_t __RPC_FAR *pwchRawName,
       /* [in] */ int cchRawName,
       /* [in] */ ISAXAttributes __RPC_FAR *pAttributes);
      virtual HRESULT STDMETHODCALLTYPE endElement(
       /* [in] */ wchar_t __RPC_FAR *pwchNamespaceUri,
       /* [in] */ int cchNamespaceUri,
       /* [in] */ wchar_t __RPC_FAR *pwchLocalName,
       /* [in] */ int cchLocalName,
       /* [in] */ wchar_t __RPC_FAR *pwchRawName,
       /* [in] */ int cchRawName);
    }

  然后我们可以重载方法startElement和endElement来进行和应用相关的特殊的处理。

  3. 通过接口ISAXXMLReader创建一个解析器。XMLReader是SAX应用实现的主要的接口,XMLReader的作用是这样的。 首先,XML的开发人员使用这个接口来注册他们对其他SAX接口的实现(比如ContentHandler,DTDHandler,ErrorHandler等等),另外,XMLREADER通过setFeature和setProperty两个方法来配置SAX解析器的行为,最后,XMLReader封装了解析的功能。示例代码如下:

   ISAXXMLReader* pRdr = NULL;
   HRESULT hr = CoCreateInstance(
      __uuidof(SAXXMLReader),
      NULL,
      CLSCTX_ALL,
      __uuidof(ISAXXMLReader),
      (void **)&pRdr);

  4. 创建相应的事件(handler)处理类,这里不妨假设我们只处理和文档内容相关的事件。示例代码如下:

  CXMLContentDeal * pMc = new CXMLContentDeal();

  注意这里CXMLContentDeal是继承接口ISAXContentHandler的类。

  5.在解析器中注册事件处理类,示例代码如下:

   hr = pRdr->putContentHandler(pMc);

  6.开始进行文档的解析,示例代码如下

   hr = pRdr->parseURL(URL); file://这里的URL是指一个具体XML文档的位置

  7.释放解析器对象

   pRdr->Release();

  以上就是基于SAX的应用程序的框架结构,我们可以看到,实际的事件处理是在我们的继承类CXMLContentDeal中实现的,在我们这个示例代码中,每当文档中一个新的元素开始的时候,都会激活方法startElement,每当一个元素结束的时候,都会激活方法endElement。我们可以在startElement和endElement中写入和应用相关的特定的代码。

posted on 2009-05-26 17:26 pear_li 阅读(336) 评论(0)  编辑 收藏 引用 所属分类: C++


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理