在处理XML文件时,经常需要一个能够快速读写数据的类。本文介绍的这个C++模板类,专注于信息管理而非验证,因此不需要其他组件即可使用。它的主要优势在于速度快,非常适合需要快速读写XML文件的场景。
与之相比,XMLDOM组件使用起来较为复杂,且速度较慢。在某些情况下,如果不需要验证XML文件,且文件内容为纯XML且不需要格式化,那么本文介绍的类将是一个不错的选择。
这个XML类是基于模板的。它需要支持两个方法:一个用于读取,一个用于写入。用户也可以从这个类派生出自己的读取或写入方法。
如果需要处理UTF-8格式的文本,那么在发送到XML类之前需要先进行转换。Unicode或ASCII格式是可以直接使用的,但其他格式需要在处理前进行转换。如果类需要管理UTF-8转换或其他类型的功能,这将影响其处理XML文件的速度。
使用XMLDOM之后创建了这个类。XML是一种非常有用的格式,用于存储信息。但是,如果每次处理XML都需要一个像XMLDOM这样的“大象”控件,那么这可能有点过于复杂。现在,使用XML变得非常简单,而且开销非常小(几乎没有)。
这个类使用起来非常简单,但其内部实现是高级的。它使用了一些通用的集合类,以及CString类。不知道为什么MFC团队没有将CString构建为一个独立的类?随着时间的推移,可能会感到有点厌倦,因为只需要CString,但却不得不包含整个MFC。作者主要使用WTL和ATL,因此解决方案是创建自己的CString。作者也喜欢编写可移植的代码。
以下是一些示例代码:
class CXMLBuffer {
public:
CXMLBuffer() : m_uIndex(0) { }
CXMLBuffer(CString string) : m_stringXML(string), m_uIndex(0) { }
CString GetXML() {
return m_stringXML;
}
void Write(const TCHAR* pszBuffer, UINT uCount, UINT* puCount) {
m_uIndex += uCount;
TCHAR* psz = m_stringXML.GetBuffer(m_uIndex + 1);
psz = &psz[m_uIndex - uCount];
memcpy(psz, pszBuffer, uCount);
psz[uCount] = '\0';
m_stringXML.ReleaseBuffer();
}
UINT Read(TCHAR* pszBuffer, UINT uCount, UINT* puCount) {
TCHAR* psz = m_stringXML.GetBuffer(0);
if (uCount + m_uIndex > m_stringXML.GetLength()) {
uCount = m_stringXML.GetLength() - m_uIndex;
}
memcpy(pszBuffer, &psz[m_uIndex], uCount);
m_uIndex += uCount;
if (puCount != NULL) {
*puCount = uCount;
}
return uCount;
}
unsigned m_uIndex;
CString m_stringXML;
};
* 示例 1 * 提取文本中的单词并插入到XML缓冲区
void Cxml1Doc::OnSampleSurroundwords() {
CString string, stringWord;
reinterpret_cast(m_viewList.GetHead())->GetWindowText(string);
if (string.IsEmpty()) {
::AfxMessageBox(_T("No text to surround, type some words"), MB_OK);
return;
}
const TCHAR* pszPosition = string;
CXMLBuffer Buffer;
CXMLArchive ar(&Buffer, CXMLArchive::eWrite);
ar << Child(_T("DOCUMENT"));
while (*pszPosition) {
if (*pszPosition <= ' ') {
if (!stringWord.IsEmpty()) {
ar << Child(_T("WORD"))
<< attribute(_T("LENGTH"), stringWord.GetLength())
<< (const TCHAR*)stringWord
<< EndNode;
}
while (*pszPosition && *pszPosition <= ' ') pszPosition++;
stringWord.Empty();
continue;
}
stringWord += *pszPosition;
pszPosition++;
}
if (!stringWord.IsEmpty()) {
ar << Child(_T("WORD"))
<< attribute(_T("LENGTH"), stringWord.GetLength())
<< (const TCHAR*)stringWord
<< EndNode;
}
ar << End;
ar.Flush();
reinterpret_cast(m_viewList.GetHead())->SetWindowText(Buffer.GetXML());
}
* 示例 2 * 向XML对象添加值
void Cxml1Doc::OnSampleHardcoded1() {
CXMLBuffer Buffer;
CXMLArchive ar(&Buffer, CXMLArchive::eWrite);
ar << Child(_T("DOCUMENT"))
<< Child(_T("CHILD"))
<< attribute(_T("A1"), 1)
<< attribute(_T("A2"), 1.1)
<< attribute(_T("A3"), _T("TEXT"))
<< _T("Value")
<< EndNode
<< Child(_T("CHILD"))
<< attribute(_T("A1"), 1)
<< attribute(_T("A2"), 1.2)
<< attribute(_T("A3"), _T("TEXT"))
<< _T("Value")
<< Child(_T("CHILD"))
<< attribute(_T("A1"), 1)
<< attribute(_T("A2"), 1.3)
<< attribute(_T("A3"), _T("TEXT"))
<< _T("Value")
<< EndNode
<< EndNode;
ar << End;
reinterpret_cast(m_viewList.GetHead())->SetWindowText(Buffer.GetXML());
}
* 示例 3 * 展示如何从格式化的XML文本中读取
void Cxml1Doc::OnSampleReadtext() {
TCHAR* pszText =
_T("")
_T("- Item value
")
_T("- Item value
")
_T("- ")
_T("
xxxxxxxx ")
_T(" ")
_T(" ");
CString stringReport;
CXMLBuffer Buffer(pszText);
CXMLArchive ar(&Buffer);
while (ar.ReadNext() == true) {
if (!ar.IsEndTag()) {
CString stringName = (const TCHAR*)ar.GetName();
stringReport += stringName;
stringReport += _T("\r\n");
if (stringName == _T("ITEM")) {
ar.PreReadNext();
CString stringNextName = (const TCHAR*)ar.GetNextName();
if (stringNextName == _T("CHILDITEM")) {
stringReport += _T("Next item is named CHILDITEM.");
if (!ar.HasNextChildren()) {
stringReport += _T("And that item doesn't have any children.");
}
stringReport += _T("\r\n");
}
}
}
}
reinterpret_cast(m_viewList.GetHead())->SetWindowText(stringReport);
}