为什么使用SAX?
因为SAX的效率较高,占用内存小,内存使用量只为一个节点的大小,所以是轻量级XML解析工具。但也由此带来了一些负面的东西,SAX是只向前的和只读的。
在数据的备份和恢复时,如果数据备份为XML形式的话,那么就可以用SAX了,因为DOCUMENT太巨大,如果备份的数据有上G的话,这根本就是不现实的。
SAX的使用
在StdAfx.h中添加:
#import <msxml3.dll> raw_interfaces_only
using namespace MSXML2;
SAX有三个接口,分别为:ISAXContentHandler、ISAXContentHandler和ISAXErrorHandler。其中ISAXContentHandler是和XML文档内容相关事件的处理接口;ISAXContentHandler是和DTD相关事件处理接口;ISAXErrorHandler出现错误时发生事件处理接口。我们根据自己的需要只要继承相应的接口,重载其函数即可。在数据恢复时,我们只对数据感兴趣,所以只要继承ISAXContentHandler即可。
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 *pwchRawName,
/* [in] */ int cchRawName,
/* [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 *pwchRawName,
/* [in] */ int cchRawName);
virtual HRESULT STDMETHODCALLTYPE characters(
/* [in] */ wchar_t __RPC_FAR *pwchChars,
/* [in] */ int cchChars);
这三个函数是我们需要重载的。注意:在characters函数中,需要将pwchChars中的字符先拷贝到一个临时wchar_t变量中,如果直接拿来使用,数据中可能会带有一些其他杂乱的数据。
char *szValue = new char[cchChars * sizeof(wchar_t) + 1];
if(!szValue)
return E_FAIL;
wchar_t *wszValue = new wchar_t[cchChars + 1];
if(!wszValue)
return E_FAIL;
memset(szValue, '/0', (cchChars * sizeof(wchar_t) + 1) * sizeof(char));
ZeroMemory(wszValue, (cchChars + 1) * sizeof(wchar_t));
//拷贝目标字符串到临时缓存
wcsncpy(wszValue, pwchChars, cchChars);
//为支持中文
WideCharToMultiByte(CP_ACP, 0, wszValue, cchChars, szValue, cchChars * sizeof(wchar_t) + 1, NULL, NULL);
if(wszValue)
{
delete[] wszValue;
wszValue = NULL;
}
if(szValue)
{
delete[] szValue;
szValue = NULL;
}
使用时很简单,如下:
CoInitialize(NULL);
ISAXXMLReaderPtr pReader = NULL;
HRESULT hr = pReader.CreateInstance(__uuidof(SAXXMLReader));
if(hr != S_OK)
return -1;
hr = pReader->putContentHandler(param.pBackUp);//将ISAXContentHandler子类对象跟SAXXMLReader关联
if(hr != S_OK)
return -1;
wchar_t URL[1000];
ZeroMemory(URL, sizeof(URL));
mbstowcs(URL, param.szBakFile, strlen(param.szBakFile));
pReader->parseURL(URL); //文件路径
Reader->putContentHandler(NULL);
注意:
XML文件中必须只有一个根节点,否则SAX只解析第一个根节点;