📄 xmldatarecordparser.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include "xmldatarecordparser.h"
#include <atlbase.h>
#define INVALID_ITEM -1
#ifdef DEBUG
VOID DumpDataRecordList(RefCountedDataRecordList *m_pDataRecordList)
{
for (INT i = 0; i < m_pDataRecordList->size(); ++i)
{
for (INT j = 0; j < m_pDataRecordList->DataRecordSize(); ++j)
{
DataRecord *p = (*m_pDataRecordList)[i];
DataRecord::string &str = (*p)[j];
DEBUGMSG(ZONE_OWAEC_PARSE_RESULTS, (L"Item %d, property %d value %s", i, j, (const WCHAR*)(str.get_buffer())));
}
}
}
#endif
/*------------------------------------------------------------------------------
ToSAXHR
According to the SAX documentation, all API's that implement ISAXContentHandler
must return either S_OK or E_FAIL. Thus all of the implementations we provide for
ContentHandler must be wrapped with these values.
Parameters:
hr: The HRESULT to cast to a SAX Hresult
Returns (HRESULT): S_OK on success or E_FAIL on failure
------------------------------------------------------------------------------*/
inline HRESULT ToSAXHR(HRESULT hr)
{
return (SUCCEEDED(hr)) ? S_OK : E_FAIL;
}
/*-----------------------------------------
Constructor/Destructor Implementation
------------------------------------------*/
CXMLDataRecordParser::CXMLDataRecordParser()
{
TRACE_(ZONE_OWAEC_TRACING_CTOR);
MemTrackAdd();
m_cRefs = 1;
m_idxCurrentParsingItem = INVALID_ITEM;
m_pCurrentDataRecord = NULL;
m_pDataRecordList = NULL;
m_piXMLReader = NULL;
};
CXMLDataRecordParser::~CXMLDataRecordParser()
{
TRACE_(ZONE_OWAEC_TRACING_CTOR);
MemTrackRemove();
ASSERT(m_pCurrentDataRecord == NULL);
if (m_piXMLReader)
{
m_piXMLReader->Release();
m_piXMLReader = NULL;
}
}
/*----------------------------------------
Public Function Implementation
------------------------------------------*/
/*------------------------------------------------------------------------------
CXMLDataRecordParser::SetDataRecordPropertyKeyword
Set a property mapping
Parameters:
idxProperty: The index of the property to be mapped
c_wszProperty: The property name tag
------------------------------------------------------------------------------*/
HRESULT CXMLDataRecordParser::SetDataRecordPropertyKeyword(INT idxProperty, const WCHAR * c_wszProperty)
{
if (idxProperty < 0 || idxProperty >= MAX_DATARECORD_PROPERTIES)
{
return E_INVALIDARG;
}
if (c_wszProperty == NULL)
{
return E_POINTER;
}
//ce::wstring assignment does a str copy
if (!m_wstrPropertyMapping[idxProperty].assign(c_wszProperty))
{
return E_OUTOFMEMORY;
}
return S_OK;
}
/*------------------------------------------------------------------------------
CXMLDataRecordParser::SetNewDataRecordKeyword
Sets the tag which will prompt the creation of a new datarecord during parsing
------------------------------------------------------------------------------*/
HRESULT CXMLDataRecordParser::SetNewDataRecordKeyword(const WCHAR * c_wszNewDataRecord)
{
if (c_wszNewDataRecord == NULL)
{
return E_POINTER;
}
//ce::wstr assign does a copy
if (!m_wstrNewDataRecordName.assign(c_wszNewDataRecord))
{
return E_OUTOFMEMORY;
}
return S_OK;
}
/*------------------------------------------------------------------------------
CXMLDataRecordParser::Parse
Parse an XML string according to the property mapping and push the results into
the given datarecordlist
Parameters:
bstrXML: The xml to parse
pDataRecordList: The datarecord list which will store the results
------------------------------------------------------------------------------*/
HRESULT CXMLDataRecordParser::Parse(BSTR bstrXML, RefCountedDataRecordList * pDataRecordList)
{
if (bstrXML == NULL || pDataRecordList == NULL)
{
return E_POINTER;
}
m_pDataRecordList = pDataRecordList;
//Stabalize the list
m_pDataRecordList->AddRef();
HRESULT hr = S_OK;
CComPtr<ISAXContentHandler> cpContentHandler;
//Create the SAXXmlReader
if (m_piXMLReader == NULL)
{
hr = CoCreateInstance(
CLSID_SAXXMLReader,
NULL,
CLSCTX_INPROC_SERVER,
IID_ISAXXMLReader,
reinterpret_cast<void **>(&m_piXMLReader)
);
}
//Get the content handler interface to give to the XMLReader
if (SUCCEEDED(hr))
{
hr = QueryInterface(
IID_ISAXContentHandler,
reinterpret_cast<void **>(&cpContentHandler)
);
}
//register the content handler with the xml reader
if (SUCCEEDED(hr))
{
ASSERT(m_piXMLReader);
hr = m_piXMLReader->putContentHandler(cpContentHandler);
}
//parse the xml
if (SUCCEEDED(hr))
{
VARIANT varParse = {0};
varParse.vt = VT_BSTR;
varParse.bstrVal = bstrXML;
hr = m_piXMLReader->parse(varParse);
}
#ifdef DEBUG
//debugout the datarecord list
DumpDataRecordList(m_pDataRecordList);
#endif
//cleanup
m_idxCurrentParsingItem = INVALID_ITEM;
m_pDataRecordList->Release();
m_pDataRecordList = NULL;
return hr;
}
HRESULT CXMLDataRecordParser::ClearMapping()
{
m_wstrNewDataRecordName.clear();
for (INT i = 0; i < MAX_DATARECORD_PROPERTIES; i++)
{
m_wstrPropertyMapping[i].clear();
}
return S_OK;
}
/*-----------------------------------------
IUnknown Implementation
------------------------------------------*/
ULONG STDMETHODCALLTYPE CXMLDataRecordParser::AddRef()
{
return ++m_cRefs;
}
ULONG STDMETHODCALLTYPE CXMLDataRecordParser::Release()
{
INT cRefs = --m_cRefs;
if (cRefs <= 0)
delete this;
return cRefs;
}
STDMETHODIMP CXMLDataRecordParser::QueryInterface(REFIID refiid, VOID **ppvObject)
{
HRESULT hr = S_OK;
if (ppvObject == NULL)
{
return E_POINTER;
}
if (refiid == IID_IUnknown)
{
(*ppvObject) = static_cast<IUnknown*>(this);
AddRef();
}
else if (refiid == IID_ISAXContentHandler)
{
(*ppvObject) = static_cast<ISAXContentHandler*>(this);
AddRef();
}
else
{
hr = E_NOINTERFACE;
}
return hr;
}
/*-----------------------------------------
ISAXContentHandler Implementation
------------------------------------------*/
/*------------------------------------------------------------------------------
CXMLDataRecordParser::characters
If we are currently inside a recognized tag, then
collect the rest of the text and store it in the current datarecord
------------------------------------------------------------------------------*/
STDMETHODIMP CXMLDataRecordParser::characters(
const WCHAR *pwchChars ,
INT cchChars
)
{
//check to see if we are in a collection state
if (m_idxCurrentParsingItem == INVALID_ITEM)
{
return S_OK;
}
//if we are, collect all the char's up the the next open angle bracket
return ToSAXHR(AddPropertyToCurrentDataRecord(
pwchChars,
cchChars
));
}
/*------------------------------------------------------------------------------
CXMLDataRecordParser::startElement
Check the current tag to see if its one we recognize. If it is one we are searching
for, do the appropriate action (e.g. on new-datarecord-tag create a new-datarecord etc).
------------------------------------------------------------------------------*/
STDMETHODIMP CXMLDataRecordParser::startElement(
const WCHAR *pwchNamespaceUri ,
INT cchNamespaceUri ,
const WCHAR *pwchLocalName ,
INT cchLocalName ,
const WCHAR *pwchQName ,
INT cchQName ,
ISAXAttributes* pAttributes
)
{
//paranoid: check parameters
if (pwchLocalName == NULL)
{
return S_OK;
}
HRESULT hr = S_OK;
//check the new datarecord tag with the local name tag
if (wcsnicmp(m_wstrNewDataRecordName, pwchLocalName, min(wcslen(m_wstrNewDataRecordName), cchLocalName)) == 0)
{
hr = CreateNewDataRecord();
}
else
{
BOOL fMatch = FALSE;
//Run through the property mapping to see if this tag matches a property we want
for (INT i = 0; i < MAX_DATARECORD_PROPERTIES; i++)
{
if (
m_wstrPropertyMapping[i][0] != 0 &&
(wcsnicmp(m_wstrPropertyMapping[i], pwchLocalName, min(wcslen(m_wstrPropertyMapping[i]), cchLocalName)) == 0)
)
{
m_idxCurrentParsingItem = i;
fMatch = TRUE;
break;
}
}
if (!fMatch)
{
m_idxCurrentParsingItem = INVALID_ITEM;
}
}
return ToSAXHR(hr);
}
/*------------------------------------------------------------------------------
CXMLDataRecordParser::endElement
If this tag is the end of the new datarecord tag, commit the current open datarecord
to the datarecord list
------------------------------------------------------------------------------*/
STDMETHODIMP CXMLDataRecordParser::endElement(
const WCHAR *pwchNamespaceURI ,
INT cchNamespaceURI ,
const WCHAR *pwchLocalName ,
INT cchLocalName ,
const WCHAR *pwchQName ,
INT cchQName
)
{
HRESULT hr = S_OK;
if (wcsnicmp(m_wstrNewDataRecordName, pwchLocalName, min(wcslen(m_wstrNewDataRecordName), cchLocalName)) == 0)
{
hr = CommitCurrentDataRecord();
}
m_idxCurrentParsingItem = INVALID_ITEM;
return ToSAXHR(hr);
}
/*-----------------------------------------
Private Functions Implementation
------------------------------------------*/
/*------------------------------------------------------------------------------
CXMLDataRecordParser::CreateNewDataRecord
Create a new datarecord to later be pushed into the datarecord list
------------------------------------------------------------------------------*/
HRESULT CXMLDataRecordParser::CreateNewDataRecord()
{
//Check that we are not adding a new datarecord when there is still an open datarecord
ASSERT(m_pCurrentDataRecord == NULL);
m_idxCurrentParsingItem = INVALID_ITEM;
return m_pDataRecordList->CreateNewDataRecord(&m_pCurrentDataRecord);
}
/*------------------------------------------------------------------------------
CXMLDataRecordParser::CommitCurrentDataRecord
Push the current datarecord into the DataRecordList
------------------------------------------------------------------------------*/
HRESULT CXMLDataRecordParser::CommitCurrentDataRecord()
{
if (m_pCurrentDataRecord == NULL)
{
ASSERT(FALSE);
return E_UNEXPECTED;
}
if (! m_pDataRecordList->push_back(m_pCurrentDataRecord) )
{
return E_OUTOFMEMORY;
}
m_pCurrentDataRecord = NULL;
m_idxCurrentParsingItem = INVALID_ITEM;
return S_OK;
}
/*------------------------------------------------------------------------------
CXMLDataRecordParser::AddPropertyToCurrentDataRecord
Add a property string to the current open datarecord
------------------------------------------------------------------------------*/
HRESULT CXMLDataRecordParser::AddPropertyToCurrentDataRecord(const WCHAR *pwchProperty, INT cchProperty)
{
if (pwchProperty == NULL)
{
return E_POINTER;
}
//check that we are in a state that can add a property
if (
m_pCurrentDataRecord == NULL ||
m_idxCurrentParsingItem < 0
)
{
ASSERT(FALSE);
return E_INVALIDARG;
}
if (!(*m_pCurrentDataRecord)[m_idxCurrentParsingItem].append(pwchProperty, cchProperty))
{
return E_OUTOFMEMORY;
}
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -