/***********************************************************************/ /* Copyright (C) 2002 Definitive Solutions, Inc. All Rights Reserved. */ /* THIS COMPUTER PROGRAM IS PROPRIETARY AND CONFIDENTIAL TO DEFINITIVE */ /* SOLUTIONS, INC. AND ITS LICENSORS AND CONTAINS TRADE SECRETS OF */ /* DEFINITIVE SOLUTIONS, INC. THAT ARE PROVIDED PURSUANT TO A WRITTEN */ /* AGREEMENT CONTAINING RESTRICTIONS ON USE AND DISCLOSURE. ANY USE, */ /* REPRODUCTION, OR TRANSFER EXCEPT AS PROVIDED IN SUCH AGREEMENT */ /* IS STRICTLY PROHIBITED. */ /***********************************************************************/ #include "stdafx.h" #include "MySax2.h" #include "Generic.h" ///////////////////////////////////////////////////////////////////////////// // MySax2 // Constructor. MySax2::MySax2() : m_pReader(NULL) , m_pLocator(NULL) { // Can be called multiple times in an application as long as a matching // CoUninitialize() (see the destructor) appears. HRESULT hr(S_OK); EC_H(::CoInitialize(NULL)); } // Destructor. /* virtual */ MySax2::~MySax2() { // Remove any objects we created. Cleanup(); // Matches the CoInitialize() (see the constructor). ::CoUninitialize(); DOMYLOGT ("MySax2 object at <%p> destructed.\n", this); } // Do cleanup. void MySax2::Cleanup() { // Release the parser object. if (m_pReader) { m_pReader->Release(); m_pReader = NULL; } } // This must be called after the constructor; must be called exactly once // during the object's lifetime. HRESULT MySax2::Initialize() { _ASSERTE(NULL == m_pReader && "Initialize() must be called only once!"); HRESULT hr(S_OK); DOMYLOGA ("Entering Initialize().\n"); // Create the SAX2 parser object. EC_H(CoCreateInstance(__uuidof(SAXXMLReader), NULL, CLSCTX_ALL, __uuidof(ISAXXMLReader), (PVOID*) &m_pReader)); // Register this object as the content hander. EC_H(m_pReader->putContentHandler(this)); // Register the error handler. EC_H(m_pReader->putErrorHandler(this)); EC_SUCCEED(("MySax2 initialization was successful.\n")); // If an error occured, we need to clean up this object, so that it can't // be used incorrectly. if (FAILED(hr)) { Cleanup(); } // Done! DOMYLOGA ("Exiting Initialize() with HRESULT <%x>.\n", hr); return hr; } // This parses the sent XML name. HRESULT MySax2::Parse(const CString& sXmlName) const { _ASSERTE(! sXmlName.IsEmpty()); _ASSERTE(NULL != m_pReader && "Initialize() must be called first!"); USES_CONVERSION; HRESULT hr(S_OK); DOMYLOGA ("Entering Parse() for <%s>.\n", sXmlName); EC_H(m_pReader->parseURL(A2W(sXmlName))); EC_FAIL(s, sXmlName); DOMYLOGA ("Exiting Parse() with hr <%x>.\n", hr); return hr; } // Receives notification of the beginning of a document. /* virtual */ HRESULT STDMETHODCALLTYPE MySax2::startDocument() { DOMYLOGA ("startDocument\n"); return S_OK; } // Receives notification of the end of a document. /* virtual */ HRESULT STDMETHODCALLTYPE MySax2::endDocument() { DOMYLOGA ("endDocument\n"); return S_OK; } // Receives notification of the beginning of an element. /* virtual */ HRESULT STDMETHODCALLTYPE MySax2::startElement( wchar_t __RPC_FAR* pwchNamespaceUri, int cchNamespaceUri, wchar_t __RPC_FAR* pwchLocalName, int cchLocalName, wchar_t __RPC_FAR* pwchRawName, int cchRawName, ISAXAttributes __RPC_FAR* pAttributes) { USES_CONVERSION; // (This section is just an example of how to get the info from the cached // Locator pointer). HRESULT hr(S_OK); int nCol(-1); EC_H(m_pLocator->getColumnNumber(&nCol)); int nLine(-1); EC_H(m_pLocator->getLineNumber(&nLine)); wchar_t* pwchPublicId = NULL; EC_H(m_pLocator->getPublicId(&pwchPublicId)); CString sPublicId(pwchPublicId); // Okay, now get info about this element and add it to the top of the stack. CString sElementName(W2A(pwchLocalName)); sElementName = sElementName.Left(cchLocalName); m_slElements.AddHead(sElementName); DOMYLOGD ("Line <%d>, Col <%d>, PublicId <%s>: startElement <%s>\n", nLine, nCol, sPublicId, sElementName); // Now get info about each of this element's attributes. int nAttrCount(0); EC_H(pAttributes->getLength(&nAttrCount)); for (int nAttr = 0; SUCCEEDED(hr) && nAttr < nAttrCount; ++nAttr) { wchar_t* pwchAttrLocalName = NULL; int nAttrLocalNameLen(0); EC_H(pAttributes->getLocalName(nAttr, &pwchAttrLocalName, &nAttrLocalNameLen)); CString sAttrLocalName(W2A(pwchAttrLocalName)); sAttrLocalName = sAttrLocalName.Left(nAttrLocalNameLen); wchar_t* pwchAttrValue = NULL; int nAttrValueLen(0); EC_H(pAttributes->getValue(nAttr, &pwchAttrValue, &nAttrValueLen)); CString sAttrValue(W2A(pwchAttrValue)); sAttrValue = sAttrValue.Left(nAttrValueLen); DOMYLOGD (" Attr <%d>: LocalName <%s>, Value <%s>\n", nAttr, sAttrLocalName, sAttrValue); } return hr; } // Receives notification of character data. /* virtual */ HRESULT STDMETHODCALLTYPE MySax2::characters( wchar_t __RPC_FAR* pwchChars, int cchChars) { USES_CONVERSION; CString sCharsSent(W2A(pwchChars)); sCharsSent = sCharsSent.Left(cchChars); // Build up the buffer - technically, this method can get called several // times per "value" (although really this is rare, we still have to // account for it). m_sCharacters += sCharsSent; return S_OK; } // Receives notification of the end of an element. /* virtual */ HRESULT STDMETHODCALLTYPE MySax2::endElement( wchar_t __RPC_FAR* pwchNamespaceUri, int cchNamespaceUri, wchar_t __RPC_FAR* pwchLocalName, int cchLocalName, wchar_t __RPC_FAR* pwchRawName, int cchRawName) { USES_CONVERSION; // (This section is just an example of how to get the info from the cached // Locator pointer). HRESULT hr(S_OK); int nCol(-1); EC_H(m_pLocator->getColumnNumber(&nCol)); int nLine(-1); EC_H(m_pLocator->getLineNumber(&nLine)); // Okay, now get info about this element. CString sLocalName(W2A(pwchLocalName)); sLocalName = sLocalName.Left(cchLocalName); DOMYLOGD ("Line <%d>, Col <%d>: endElement <%s>\n", nLine, nCol, sLocalName); // Since we're done with this element, let's pop it off the stack. m_slElements.RemoveHead(); // Since we're done with this element, it's time to clear the buffer out, // so it can be repopulated by the call(s) to characters(). m_sCharacters.Empty(); return hr; } // Receives an interface for locating the origin of SAX (Simple API for XML) // document events. The reader supplies a locator to the application by // invoking this method before invoking any other methods in the // ISAXContentHandler interface. This locator allows the application to // determine the end position of any document-related event, even if the // parser is not reporting an error. /* virtual */ HRESULT STDMETHODCALLTYPE MySax2::putDocumentLocator( ISAXLocator __RPC_FAR *pLocator) { _ASSERTE(pLocator); m_pLocator = pLocator; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // ISAXErrorhandler // Receives notification of a recoverable error. Microsoft says: "This // method is not called in the current SAX2 (Simple API for XML) // implementation... Currently, all errors are fatal." /* virtual */ HRESULT STDMETHODCALLTYPE MySax2::error( ISAXLocator __RPC_FAR* pLocator, unsigned short * pwchErrorMessage, HRESULT errCode) { _ASSERTE(! "SAX2 recoverable error - this should not be called!"); return S_OK; } // Receives notification of a non-recoverable error. /* virtual */ HRESULT STDMETHODCALLTYPE MySax2::fatalError( ISAXLocator __RPC_FAR* pLocator, unsigned short * pwchErrorMessage, HRESULT errCode) { _ASSERTE(pLocator == m_pLocator && "The one passed better be the same as the one we've stored"); _ASSERTE(! "SAX2 non-recoverable error!"); USES_CONVERSION; HRESULT hr(S_OK); // Get the info from the Locator. int nCol(-1); EC_H(pLocator->getColumnNumber(&nCol)); int nLine(-1); EC_H(pLocator->getLineNumber(&nLine)); wchar_t* pwchPublicId = NULL; EC_H(pLocator->getPublicId(&pwchPublicId)); CString sPublicId(pwchPublicId); wchar_t* pwchSystemId = NULL; EC_H(pLocator->getSystemId(&pwchSystemId)); CString sSystemId(pwchSystemId); EC_SUCCEED(("SystemId <%s>, PublicId <%s>, Line <%d>, Column <%d>\n", sSystemId, sPublicId, nLine, nCol)); EC_SUCCEED(("ErrCode <%x>, Error Message: %s", errCode, W2A(pwchErrorMessage))); return hr; } // Receives notification of a warning. Microsoft says: "This method is not // called in the current SAX2 (Simple API for XML) implementation." /* virtual */ HRESULT STDMETHODCALLTYPE MySax2::ignorableWarning( ISAXLocator __RPC_FAR* pLocator, unsigned short * pwchErrorMessage, HRESULT errCode) { _ASSERTE(! "SAX2 ignorable warning - this should not be called!"); return S_OK; }