C++ を使用した SAX2 アプリケーション作成のジャンプスタート

C++ を使用した SAX2 アプリケーション作成のジャンプスタート

Microsoft Corporation

November 2000

download sample code この記事のサンプル コードをダウンロードする。 (136 KB)

サンプル コードをオンラインで参照する。

概要 : この記事では、Microsoft XML Parser (MSXML) における Simple API for XML (SAX2) の実装方法を紹介しており、SAX2 を使ったアプリケーション構築を始める際の参考となります。また、XML 文書を読み込み、タグをコンソールに出力する C++ アプリケーションをすばやく構築する方法について説明します。

注 : このチュートリアルを実行するには、最新の製品版の Microsoft XML Parser (MSXML) が必要です。これは、XML Developer Center から入手可能です。

Contents

ジャンプスタート アプリケーション (C++) の概要
ContentHandler の実装
メイン プログラムの作成
メイン プログラムの全コード

ジャンプスタート アプリケーション (C++) の概要

SAX2 は「プッシュ モデル」のパーサーです。SAX2 が文書を検証する際には、SAXXMLReader (SAX2 reader) が文書を読み、一連のイベントを実装済みのイベントハンドラに渡します。SAX2 リーダーはいくつかのカテゴリのイベントを生成します。 次のようなイベントを含みます。

  • XML 文書の内容の中で発生するイベント。
  • 文書型定義 (DTD) 中で発生するイベント。
  • エラーとして発生するイベント。

そのようなイベントを処理するには、適切なイベントを処理するメソッドを含んだ対応するハンドラ クラスを実装する必要があります。自分が処理したいイベント用のハンドラを実装するだけでよいです。もし特定の種類のイベントを処理するハンドラを実装しないのであれば、リーダーは単にそのイベントを無視します。

ジャンプスタート アプリケーションは、実装しなければならない 2 つの主要なコンポーネントを含みます。

コンポーネント 説明
ContentHandler ISAXContentHandler インターフェイスを実装します。ContentHandler は、XML 文書の主要なコンテンツを処理するメソッドを提供するクラスです。SAX2 が文書を検証する際に、リーダーは、ContentHandler に一連のイベントを渡します。例えば、文書中のそれぞれの要素については、リーダーは startElementおよび、CharactersendElement を渡します。これらのイベントを処理するには、リーダーから受け取った情報を処理する ContentHandler 内のメソッドにコードを追加します。
メイン プログラム
  1. SAX2 リーダー (SAXXMLReader) のインスタンス生成。
  2. ContentHandler のインスタンス生成。
  3. リーダー に対する ContentHandler の設定。
  4. XML 文書のソースの設定。
  5. 検証作業の開始。

ジャンプスタート アプリケーションを作成するには、まず最初に、ISAXContentHandler インターフェイスを拡張するハンドラ クラスを実装しなければなりません。C++ を使ってクラスを作成できますが、完全な機能を持つ COM オブジェクトは作成できません。このクラスのメソッドの内で、イベントの通知を受け取った際には何をすべきかアプリケーションに伝えます。ContentHandler クラスを実装した後に、SAXXMLReader のインスタンスの生成、ContentHandler の設定、検証を開始するメイン プログラムの作成を行います

ContentHandler の実装

SAX2 アプリケーションを作成する第 1 段階は、ハンドラ クラスの実装です。この例では、ISAXContentHandler インターフェイスから派生した ContentHandler だけを実装します。

ヘッダ ファイルの作成

SAX2 を使用する際には、ContentHandler が最も便利なハンドラ クラスです。ISAXContentHandler インターフェイスからこのクラスを派生させます。

MSXML 由来の SAX2 インターフェイスを使用するには、次のようなコードを使ってインターフェイスを宣言しなければなりません。

#import <msxml3.dll> raw_interfaces_only 
using namespace MSXML2;

注 : ジャンプスタート アプリケーション用に、StdAfx.h ファイルの中でインターフェイスを宣言します。

ContentHandler を実装するには、"MyContent.h" という名前のヘッダ ファイルを作成します。次のようなサンプル コードの中で示します。

#include "SAXContentHandlerImpl.h"

class MyContent : public SAXContentHandlerImpl  
{
public:
    MyContent();
    virtual ~MyContent();
        
        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 *pwchQName,
            /* [in] */ int cchQName,
            /* [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 *pwchQName,
            /* [in] */ int cchQName);

        virtual HRESULT STDMETHODCALLTYPE startDocument();

private:
        void prt(
            /* [in] */ const wchar_t * pwchFmt,
            /* [in] */ const wchar_t __RPC_FAR *pwchVal,
            /* [in] */ int cchVal);
        int idnt;
};

#endif // !defined(AFX_MYCONTENT_H__E1B3AF99_0FA6_44CD_82E3_55719F9E3806__INCLUDED_)

MyContent クラスの作成

MyContent.h ファイルを作成した後に、次の段階は MyContent という名前の ContentHandler クラスの実装です。

#include "stdafx.h"
#include "MyContent.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

MyContent::MyContent()
{
    idnt = 0;
}

MyContent::~MyContent()
{

}

HRESULT STDMETHODCALLTYPE MyContent::startElement( 
            /* [in] */ wchar_t __RPC_FAR *pwchNamespaceUri,
            /* [in] */ int cchNamespaceUri,
            /* [in] */ wchar_t __RPC_FAR *pwchLocalName,
            /* [in] */ int cchLocalName,
            /* [in] */ wchar_t __RPC_FAR *pwchQName,
            /* [in] */ int cchQName,
            /* [in] */ ISAXAttributes __RPC_FAR *pAttributes)
{
    HRESULT hr = S_OK;
    int l;
    printf("\n%*s",3 * idnt++, "");
    prt(L"<%s",pwchLocalName,cchLocalName);
    pAttributes->getLength(&l);
    for ( int i=0; i<l; i++ ) {
        wchar_t * ln, * vl; int lnl, vll;
        pAttributes->getLocalName(i,&ln,&lnl); 
        prt(L" %s=", ln, lnl);
        pAttributes->getValue(i,&vl,&vll);
        prt(L"\"%s\"", vl, vll);
    }
    printf(">");

    // A little example, how to abort parse
    if ( wcsncmp(pwchLocalName,L"qu",2) == 0 ) {
        printf("\n<qu> tag encountered, parsing aborted.");
        hr = E_FAIL;
    }

    return hr;
}
        
       
HRESULT STDMETHODCALLTYPE MyContent::endElement( 
            /* [in] */ wchar_t __RPC_FAR *pwchNamespaceUri,
            /* [in] */ int cchNamespaceUri,
            /* [in] */ wchar_t __RPC_FAR *pwchLocalName,
            /* [in] */ int cchLocalName,
            /* [in] */ wchar_t __RPC_FAR *pwchQName,
            /* [in] */ int cchQName)
{
    printf("\n%*s",3 * --idnt, "");
    prt(L"</%s>",pwchLocalName,cchLocalName);
    return S_OK;
}

HRESULT STDMETHODCALLTYPE MyContent::startDocument()
{
    printf("<?xml version=\"1.0\" ?>");
    return S_OK;
}
        
void MyContent::prt(
            /* [in] */ const wchar_t * pwchFmt,
            /* [in] */ const wchar_t __RPC_FAR *pwchVal,
            /* [in] */ int cchVal)
{
    static wchar_t val[1000];
    cchVal = cchVal>999 ? 999 : cchVal;
    wcsncpy( val, pwchVal, cchVal ); val[cchVal] = 0;
    wprintf(pwchFmt,val);
}

メイン プログラムの作成

最後に次のようなことを実行するメイン プログラムを作成します。

  • コマンド プロンプト インターフェイスの提供。
  • ISAXXMLReader インターフェイス を実装するクラスをインスタンス化することで、パーサー を生成します。
  • Creates a ContentHandler by instantiating the MyContent クラスをインスタンス化することによって ContentHandler を生成します。
  • パーサーに ContentHandler を登録します。

メイン プログラムの全コード

プログラムのコードを次に示します。

#include "stdafx.h"

#include "MyContent.h"
#include "SAXErrorHandlerImpl.h"

int main(int argc, char* argv[])
{
    if (argc<2) {
        printf("\nTry something like\n\ttestSax _
          file:///drive:/path/file.xml\nGood luck!\n");
        return 0;    // Need URL to read
    }

    CoInitialize(NULL); 
    ISAXXMLReader* pRdr = NULL;

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

    if(!FAILED(hr)) 
    {
        MyContent * pMc = new MyContent();
        hr = pRdr->putContentHandler(pMc);

        // No sense to do so in this example, just an illustration how to _
           set other handlers
        //=========================================================================
         SAXErrorHandlerImpl * pEc = new SAXErrorHandlerImpl();
         hr = pRdr->putErrorHandler(pEc);
        // SAXDTDHandlerImpl * pDc = new SAXDTDHandlerImpl();
        // hr = pRdr->putDTDHandler(pDc);


        static wchar_t URL[1000];
        mbstowcs( URL, argv[1], 999 );
        wprintf(L"\nParsing document: %s\n", URL);
        
        hr = pRdr->parseURL(URL);
        printf("\nParse result code: %08x\n\n",hr);
    
        pRdr->Release();
    }
    else 
    {
        printf("\nError %08X\n\n", hr);
    }

    CoUninitialize();
    return 0;
}

ジャンプスタート アプリケーションの実行

コマンド プロンプトから次のように入力します。

pathname\debug\cppsaxsample.exe test.xml

上のコードでは、pathname はジャンプスタート アプリケーション ファイルをダウンロードしたフォルダのパス名です。test.xml ファイルは、ダウンロードで提供されているテストファイルです。 検証済みの test.xml ファイルは、コマンド プロンプト ウィンドウに現れるでしょう。