独上高楼网站
  •    你所在位置:首页 VS.netXMLXML经验〉XML 开发人员的 SAX2 快速入门
  • XML 开发人员的 SAX2 快速入门
  • 作者:佚名  文章来源:http://msdn2.microsoft.com/zh-cn/default.aspx  发布日期:2007-07-07  浏览次数:678
  • 打印这篇文章
  • 什么是 SAX2?

    SAX2,即 Simple API for XML,是基于事件的 XML 分析的标准接口的最新版本。SAX2 提供了使用“文档对象模型 (DOM)”处理 XML 文档的快速、低内存的另一种方法。在使用 DOM 分析 XML 文件时,它在内存中建立了完整的文档树。相比而言,SAX2 将遍历文档,并将新元素的开始或结束等通知分析事件的调用应用程序。使用 SAX2 的一个最佳功能是分析长文档。例如,用 SAX2 分析器,应用程序可以监视发生的事件,只将文档中必要的部分读入内存。

    Microsoft 在 MSXML3.DLL 中为 SAX2 接口提供了完全兼容的 COM 实现 (MSXML SAX2) 。作为对 MSXML SAX2 的快速简介,并且为了帮助您开始用它的接口来建立应用程序,本文介绍如何快速建立“骨架”应用程序,它使用 MSXML SAX2 读取 XML 文档,并在控制台上打印文档的标记。在理解了用 MSXML SAX2 建立应用程序的基本原理之后,无疑您会清楚如何利用基于事件的分析建立应用程序。

    如何使用 MSXML SAX2?

    SAX2 是一种“推进模型”分析器。换句话说,您提供了许多处理程序,而在发生特定事件时(例如开始一个文档,或一个元素的开始和结束),分析器便调用您提供的处理程序。SAX2 分析器生成一些种类的事件,包括在 XML 文档内容中发生的事件、在 DTD 中发生的事件和错误事件。要处理这些事件,必须实现相应的处理程序类,它包含处理相应事件的方法。请注意,您只需要为这些要处理的事件实现处理程序。如果没有为特定类型的事件实现处理程序,那么该事件将被忽略。

    例如,本文中介绍的“命令行”应用程序只有一个处理程序 — 内容处理程序,它是通过实现扩展 ISAXContentHandler 接口的类创建的。请注意,在 Visual C++ 中不需要创建功能完整的 COM 对象。对于您创建的每个处理程序类来说,需要实现响应 XML 分析事件的方法。

    在为要处理的事件创建了必要的处理程序类之后:

    1. 创建 SAXXMLReader 实例。

    2. 设置处理程序类。

    3. 设置 XML 文档的来源。

    4. 开始分析。

    在分析器读取 XML 文档时,它将调用包含在实现的处理程序中的方法。

    “快速入门”应用程序代码

    正如以前所提到的,本文将介绍如何建立非常简单的命令行应用程序,它能够读取 XML 文件,并将文件的标记打印到控制台窗口。应用程序只实现了内容处理程序。应用程序包括下列文件:

    • MyContent.h 内容处理程序的头文件。

    • MyContent.cpp 内容处理程序的实现。

    • TestSax.cpp “命令行”控制台应用程序。

    内容处理程序头文件

    为了实现内容处理程序,必须首先为它创建头文件。我们为该应用程序调用文件 MyContent.h。

    #include xmlsax.h"     //  包括头文件。
    class MyContent : public ISAXContentHandler 
    {
       public:
          MyContent();    // 定义建立函数和解除函数。
          virtual ~MyContent();
    
          // 从 ISAXContentHandler 复制所有的方法。
          // 接口...
          virtual HRESULT STDMETHODCALLTYPE StartDocument(void);
          virtual HRESULT STDMETHODCALLTYPE EndDocument(void);
          virtual HRESULT STDMETHODCALLTYPE StartPrefixMapping(const
             wchar_t__RPC_FAR *pwchPrefix,int cchPrefix,const 
             wchar_t __RPC_FAR *pwchUri,int cchUri);
    
          // ...和底层的 IUnknown 接口...
          long __stdcall QueryInterface(const struct _GUID &,void ** );
          unsigned long __stdcall AddRef(void);
          unsigned long __stdcall Release(void);
    
          // ...和添加任何内容来简化实现。
          private:
             void prt ( char * pszFmt, const wchar_t __RPC_FAR *pwchVal, int
                cchVal);
    };
    

    内容处理程序实现

    下一步是实现 MyContent 类。该文件也相对简单。

    #include "stdafx.h"   // 我们需要头文件...
    #include 
    #include 
    #include "MyContent.h"
    
    // 通常在建立函数和解除函数中不需任何操作, 
    // 但如果有的话,则在此完成。
    MyContent::MyContent()  {}    
    MyContent::~MyContent() {}  
    
    // 现在完成 IUnknown 填充。
    // (然而,请牢记,若希望将处理程序作为 COM 对象来实现,
    //  可以添加比用这些方法显示的
    //  更多的功能)
    long __stdcall MyContent::QueryInterface(const struct _GUID &,void ** )
          { return 0; }
    unsigned long __stdcall MyContent::AddRef() { return 0; }
    unsigned long __stdcall MyContent::Release() { return 0; }
    
    //现在开始着手业务。
    // 首先确定您需要的和不需要的事件。
    // 对于不需要的方法,处理很简单:
    HRESULT STDMETHODCALLTYPE MyContent::StartDocument()
    {
       return S_OK;   // 返回 S_OK 以继续。
                      // 任何返回的错误代码都将中止语法分析。
    }
    
    // 对于需要的事件,您可随意处理!
    HRESULT STDMETHODCALLTYPE MyContent::StartElement( 
          /* [in] */ const wchar_t __RPC_FAR *pwchNamespaceUri,
          /* [in] */ int cchNamespaceUri,
          /* [in] */ const wchar_t __RPC_FAR *pwchLocalName,
          /* [in] */ int cchLocalName,
          /* [in] */ const wchar_t __RPC_FAR *pwchRawName,
          /* [in] */ int cchRawName,
          /* [in] */ ISAXAttributes __RPC_FAR *pAttributes)
    {
    //我想打印标志名称。
       prt("\n<%s>",pwchLocalName,cchLocalName);  
       return S_OK;
    }
    
    //“prt” 是一个专用方法。
    // SAX 不使用它。您不必实现它和任何其他
    // 专用方法。
    // 这仅是快速打印。
    void MyContent::prt ( char * pszFmt, const wchar_t __RPC_FAR *pwchVal, int cchVal )
    {
       static wchar_t fmt[1000], val[1000];
       mbstowcs( fmt, pszFmt, 999 ); fmt[999] = 0;
       wcsncpy( val, pwchVal, (cchVal>999?999:cchVal+1) ); val[999] = 0;
       wprintf(fmt,val);
    }
    

    主程序

    最后,创建了启动整个过程的“主程序”。它提供了命令行接口,通过实例化实现 SAXXMLReader 接口的类来创建分析器,通过实例化 MyContent 类来创建内容处理程序,并且在分析器中注册了内容处理程序。

    #include "stdafx.h"  // 您再次需要头文件。
    
    #include "stdio.h"  // 这只是在打印时需要。
    #include "xmlsax.h"
    #include "xmlsax_i.c"  // 这不是真正的头文件。
                           // 建议单独对其编译。在此
                           // 只是提醒您必须编译才能获得
                           // 常数。
    #include "MyContent.h"
    
    int main(int argc, char* argv[])    // 开始!
    {
          CoInitialize(NULL);     // 启动 COM 有点不可思议。您可能
                                  // 想使用 CoInitializeEx。
    
       ISAXXMLReader* pRdr = NULL;    // 创建分析程序。(会更不可思议...)
       HRESULT hr = CoCreateInstance(CLSID_SAXXMLReader, NULL, CLSCTX_ALL,
             IID_ISAXXMLReader, (void **)&pRdr);
    
       if(!FAILED(hr)) 
       {
          MyContent * pMc = new MyContent();    // 设置您自己的内容
                                                // 处理程序(以及
                                                // 其他程序)。
          hr = pRdr->PutContentHandler(pMc);    // 在现实中,请检查
                                                // 此 hr!
    
          static wchar_t URL[1000];        // ParseURL 应是 Unicode 字符串,
                                           // argv[1] 是 ASCII。
          mbstowcs( URL, argv[1], 999 );   // 验证您是否有 argv[1]。
    
          hr = pRdr->ParseURL(URL,-1);    // 以及语法分析!
    
          pRdr->Release();             // 现在只有一些清除工作...
       }
       else {
          printf("\nUh-oh... %08X\n\n", hr);  // 希望这不会发生, 
                                              // 但是要作好准备。
       }
    
       CoUninitialize();   // 最后,再一次, 
                           // 未初始化 COM 有点不可思议。
       return 0;
    }
    

    下一步

    本文的目的是简单介绍 SAX2,介绍可以作为您自己应用程序起点的应用程序。有关 MSXML SAX2 接口的详细信息,请参阅“2000 年 5 月技术预览”所附的“Microsoft XML SDK 3.0”中的“SAX2 开发人员指南”和“SAX2 参考”。有关处理程序实现的其他代码示例,请下载本文提供的示例代码。


  • 打印这篇文章
  • 与本文主题相关的文章
  • 返回首页