由于所有受支持的 Windows 版本(包括 Windows XP SP3)都包含 MSXML 6.0,因此您应该使用 MS XML 6.0。你应该实现自己的ISAXContentHandler 类,通常我实现一个ISequentialStream 类。
用于解析的 ISequentialStream 实现:
class MySequentialStream : public ISequentialStream
{
public:
MySequentialStream( istream &is )
: is(is), ref_count(0)
{
InitializeCriticalSection( &this->critical_section );
};
virtual ~MySequentialStream( void )
{
DeleteCriticalSection( &this->critical_section );
}
virtual HRESULT __stdcall QueryInterface( const IID &riid, void ** ppvObject )
{
if ( riid == IID_ISequentialStream )
{
*ppvObject = static_cast<void*>(this);
this->AddRef();
return S_OK;
}
if (riid == IID_IUnknown)
{
*ppvObject = static_cast<void*>(this);
this->AddRef();
return S_OK;
}
*ppvObject = 0;
return E_NOINTERFACE;
};
virtual ULONG __stdcall AddRef( void )
{
return InterlockedIncrement(&this->ref_count);
};
virtual ULONG __stdcall Release( void )
{
ULONG nRefCount = InterlockedDecrement(&this->ref_count);
if ( nRefCount == 0 ) delete this;
return nRefCount;
};
virtual HRESULT __stdcall Read( void *pv, ULONG cb, ULONG *pcbRead )
{
EnterCriticalSection( &this->critical_section );
this->is.read( reinterpret_cast<char*>(pv), cb );
*pcbRead = static_cast<ULONG>( this->is.gcount() );
LeaveCriticalSection( &this->critical_section );
return S_OK;
};
virtual HRESULT __stdcall Write( void const *pv, ULONG cb, ULONG *pcbWritten )
{
*pcbWritten = cb;
return S_OK;
};
private:
istream &is;
CRITICAL_SECTION critical_section;
ULONG ref_count;
};
你也应该实现一个 ISAXContentHandler 类(当然你应该在需要的时候填充方法):
class MyContentHandler : public ISAXContentHandler
{
public:
MyContentHandler( void )
: ref_count(0)
{};
virtual ~MyContentHandler( void ) {};
virtual HRESULT __stdcall QueryInterface( const IID &riid, void ** ppvObject )
{
if ( riid == __uuidof(ISAXContentHandler) )
{
*ppvObject = static_cast<void*>(this);
this->AddRef();
return S_OK;
}
if (riid == IID_IUnknown)
{
*ppvObject = static_cast<void*>(this);
this->AddRef();
return S_OK;
}
*ppvObject = 0;
return E_NOINTERFACE;
};
virtual ULONG __stdcall AddRef( void )
{
return InterlockedIncrement(&this->ref_count);
};
virtual ULONG __stdcall Release( void )
{
ULONG nRefCount = InterlockedDecrement(&this->ref_count);
if ( nRefCount == 0 ) delete this;
return nRefCount;
};
virtual HRESULT __stdcall putDocumentLocator( ISAXLocator * pLocator) { return S_OK; };
virtual HRESULT __stdcall startDocument( void ) { return S_OK; };
virtual HRESULT __stdcall endDocument( void ) { return S_OK; };
virtual HRESULT __stdcall startPrefixMapping( const wchar_t *pwchPrefix, int cchPrefix, const wchar_t *pwchUri, int cchUri ) { return S_OK; };
virtual HRESULT __stdcall endPrefixMapping( const wchar_t *pwchPrefix, int cchPrefix) { return S_OK; };
virtual HRESULT __stdcall startElement( const wchar_t *pwchNamespaceUri, int cchNamespaceUri, const wchar_t *pwchLocalName, int cchLocalName, const wchar_t *pwchQName, int cchQName, ISAXAttributes *pAttributes ) { return S_OK; };
virtual HRESULT __stdcall endElement( const wchar_t *pwchNamespaceUri, int cchNamespaceUri, const wchar_t *pwchLocalName, int cchLocalName, const wchar_t *pwchQName, int cchQName) { return S_OK; };
virtual HRESULT __stdcall characters( const wchar_t *pwchChars, int cchChars) { return S_OK; };
virtual HRESULT __stdcall ignorableWhitespace( const wchar_t *pwchChars, int cchChars) { return S_OK; };
virtual HRESULT __stdcall processingInstruction( const wchar_t *pwchTarget, int cchTarget, const wchar_t *pwchData, int cchData) { return S_OK; };
virtual HRESULT __stdcall skippedEntity( const wchar_t *pwchName, int cchName) { return S_OK; };
protected:
ULONG ref_count;
};
然后你可以很容易地解析一个流:
bool ParseStream( istream &is )
{
if ( FAILED(CoInitialize(NULL)) )
return false;
ISAXXMLReader * reader = 0;
if ( FAILED( CoCreateInstance( __uuidof(SAXXMLReader60), NULL, CLSCTX_ALL, __uuidof(ISAXXMLReader),(void**) &reader ) ) )
{
CoUninitialize()
return false;
}
ISequentialStream * my_stream = new MySequentialStream(is);
ISAXContentHandler * content_handler = new MyContentHandler;
my_stream->AddRef();
content_handler->AddRef();
if ( FAILED( reader->putContentHandler( content_handler ) ) )
{
my_stream->Release();
content_handler->Release();
reader->Release();
return false;
}
VARIANT var;
var.vt = VT_UNKNOWN;
var.punkVal = my_stream;
VARIANT_BOOL success = FALSE;
bool value = SUCCEEDED( reader->parse( var ) );
my_stream->Release();
content_handler->Release();
reader->Release();
return ( value && ( success != VARIANT_FALSE ) );
}