Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

MSXMLでSAX

タグ: C++ VS2005

VC++でSAXを使いたくなった。
パーサはなんでもいいのだが、まあとりあえず手近なMSXMLで。
MSXMLはDOMは使ったことがあるが、SAXはない。
でもまあ、MSDNのサンプルを見る限り、なんとかなるだろう。

まずはDOMの時同様、MSXMLのDLLを #import する。

#import <msxml6.dll>

でもって ISAXContentHandler を実装……ってあれ?
#import によって生成された msxml6.tlh の ISAXContentHandler の文字列引数がみんな unsigned short* だ。

struct __declspec(uuid("1545cdfa-9e4e-4497-a8a4-2bf7d0112c44"))
ISAXContentHandler : IUnknown
{
    //
    // Wrapper methods for error-handling
    //

    HRESULT putDocumentLocator (
        struct ISAXLocator * pLocator );
    HRESULT startDocument ( );
    HRESULT endDocument ( );
    HRESULT startPrefixMapping (
        unsigned short * pwchPrefix,
        int cchPrefix,
        unsigned short * pwchUri,
        int cchUri );

VC6ならともかく、VC8は既定では unsigned short と wchar_t を区別するから、この引数を文字列として扱うには reinterpret_cast しなきゃいけない。
それは気分的に嫌なので、仕方ないから方針変更。
atlsoap.h を #include する。
このヘッダには、 ISAXContentHandler を空実装する ISAXContentHandlerImpl が含まれるので、それを継承すれば、ただ S_OK を返すだけの実装はいちいち書かなくて済む。

#include <atlsoap.h>

class MyContentHandlerBase :
	public ISAXContentHandlerImpl,
	public CComObjectRoot
{
public:
BEGIN_COM_MAP(MyContentHandlerBase)
	COM_INTERFACE_ENTRY(ISAXContentHandler)
END_COM_MAP()

	STDMETHOD(startElement)( 
		const wchar_t  * /*wszNamespaceUri*/,
		int /*cchNamespaceUri*/,
		const wchar_t  * wszLocalName,
		int cchLocalName,
		const wchar_t  * /*wszQName*/,
		int /*cchQName*/,
		ISAXAttributes  * /*pAttributes*/
	);

	STDMETHOD(endElement)( 
		const wchar_t  * /*wszNamespaceUri*/,
		int /*cchNamespaceUri*/,
		const wchar_t  * wszLocalName,
		int cchLocalName,
		const wchar_t  * /*wszQName*/,
		int /*cchQName*/
	);

	STDMETHOD(characters)(
		 const wchar_t  * wszChars,
		 int cchChars
	);

	STDMETHOD(startDocument)();
};

typedef CComObject<MyContentHandlerBase>  MyContentHandler;

さっきは「仕方ない」とか言ったが、むしろこれとか msxml.h を #include して使うのが、MSXMLに関しては正道なのかもしれない。
私としては、 high-level properties and methods が定義される #import の方が好きなのだが。

ISAXContentHandler を実装したら、あとはそれを ISAXXMLReader に渡してパース開始。
エラー処理は面倒だから、今回はいいや。

void parse(const _TCHAR* url)
{
	CComPtr<ISAXXMLReader> ipSAXXMLReader;

	::CoCreateInstance(
		__uuidof(SAXXMLReader), 
		NULL, 
		CLSCTX_ALL, 
		__uuidof(ISAXXMLReader), 
		reinterpret_cast<void**>(&ipSAXXMLReader)
	);

	CComPtr<ISAXContentHandler> ipContentHandler;
	{
		MyContentHandler* pMyContentHandler;
		MyContentHandler::CreateInstance(&pMyContentHandler);
		ipContentHandler = pMyContentHandler;
	}

	ipSAXXMLReader->putContentHandler(ipContentHandler);
	ipSAXXMLReader->parseURL(CComBSTR(url));
}
スポンサーサイト

コメント

コメントの投稿

コメントの投稿
管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://idlysphere.blog66.fc2.com/tb.php/108-70c34147
この記事にトラックバックする(FC2ブログユーザー)

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。