您的位置:首页 > 编程语言 > C语言/C++

VC++ 下使用 xml 文件导入导出数据

2008-07-29 21:57 671 查看
XML (eXtensible Markup Language) 是一种简单的数据存储语言,使用一系列简单的标记描述数据,虽然XML占用的空间比二进制数据要占用更多的空间,但XML极其简单易于掌握和使用。更重要的是,xml 可以描述非常复杂的数据结构,比如树状结构。

为了建立一个通用,易于扩展,易于使用的数据导入导出应用,首先得定义一些数据类型用于存储 int, float, string, array 等基本数据类型。

#pragma once
#include "Collection.h"

class CDataType
{
public:
CString Id;
CDataType(void) {}
virtual ~CDataType() {}
virtual char* GetTypeName() { return ""; }
virtual int& Integer() { ::AfxThrowInvalidArgException(); }
virtual float& Float() { ::AfxThrowInvalidArgException(); }
virtual CString& String() { ::AfxThrowInvalidArgException(); }
virtual CDataType& operator[](LPCTSTR key) { ::AfxThrowInvalidArgException(); }
virtual CDataType& operator[](int index) { ::AfxThrowInvalidArgException(); }
virtual bool IsCollection() { return false; }
virtual CString& ToXML(CString& s) { return s; }
};

class CIntegerType: public CDataType
{
int m_Object;
public:
CIntegerType(int value) { m_Object = value; }
virtual char* GetTypeName() { return "INT"; }
virtual int& Integer() { return m_Object; }
virtual CString& ToXML(CString& s) {
s.Format("<INT ID=/"%s/" V=/"%d/" />", Id, m_Object);
return s;
}
};

class CFloatType: public CDataType
{
float m_Object;
public:
CFloatType(float value) { m_Object = value; }
virtual char* GetTypeName() { return "FLOAT"; }
virtual float& Float() { return m_Object; }
virtual CString& ToXML(CString& s) {
s.Format("<FLOAT ID=/"%s/" V=/"%g/" />", Id, m_Object);
return s;
}
};

class CStringType: public CDataType
{
CString m_Object;
public:
CStringType(LPCTSTR value) { m_Object = value; }
virtual char* GetTypeName() { return "STR"; }
virtual CString& String() { return m_Object; }
virtual CString& ToXML(CString& s) {
s.Format("<STR ID=/"%s/" V=/"%s/" />", Id, m_Object);
return s;
}
};

class CStringArrayType: public CDataType
{
CArray<CString*, CString*> m_Object;
public:
CStringArrayType() {}
virtual char* GetTypeName() { return "STRs"; }
void Add(LPCTSTR value) { m_Object.Add(new CString(value)); }
CString& GetAt(int index) { return *m_Object[index]; }
int GetCount() { return (int) m_Object.GetCount(); }
virtual ~CStringArrayType(void) { for (int i=0; i<m_Object.GetCount(); i++) delete m_Object[i]; }
virtual CString& ToXML(CString& s) {
s.Format("<STRs ID=/"%s/"", Id);
for (int i=0; i<m_Object.GetCount(); i++) {
s.Format("%s V%d=/"%s/"", s, i, GetAt(i));
}
return s;
}
};

class CIntegerArrayType: public CDataType
{
CArray<int, int&> m_Object;
public:
virtual char* GetTypeName() { return "INTs"; }
int& GetAt(int index) { return m_Object[index]; }
void Add(int value) { m_Object.Add(value); }
int GetCount() { return (int) m_Object.GetCount(); }
virtual CString& ToXML(CString& s) {
s.Format("<INTs ID=/"%s/"", Id);
for (int i=0; i<m_Object.GetCount(); i++) {
s.Format("%s V%d=/"%d/"", s, i, GetAt(i));
}
return s;
}
};

class CFloatArrayType: public CDataType
{
CArray<float, float&> m_Object;
public:
virtual char* GetTypeName() { return "FLOATs"; }
void Add(float value) { m_Object.Add(value); }
float& GetAt(int index) { return m_Object[index]; }
int GetCount() { return (int) m_Object.GetCount(); }
virtual CString& ToXML(CString& s) {
s.Format("<INTs ID=/"%s/"", Id);
for (int i=0; i<m_Object.GetCount(); i++) {
s.Format("%s V%d=/"%g/"", s, i, GetAt(i));
}
return s;
}
};

class CCollectionType: public CDataType
{
CCollection<CDataType> m_Object;

public:
CCollectionType() {}
virtual ~CCollectionType(void) { DeleteAll(); }
virtual CCollectionType& Collection() { return *this; }
virtual char* GetTypeName() { return "SETs"; }
virtual bool IsCollection() { return true; }

void Add(LPCTSTR key, CDataType* object) { m_Object.Add(key, object)->Id = key; }
void Add(LPCTSTR key, int value) { m_Object.Add(key, new CIntegerType(value))->Id = key; }
void Add(LPCTSTR key, float value) { m_Object.Add(key, new CFloatType(value))->Id = key; }
void Add(LPCTSTR key, LPCTSTR value) { m_Object.Add(key, new CStringType(value))->Id = key; }

int GetCount() { return m_Object.GetCount(); }
CDataType& operator[](LPCTSTR key) { return m_Object[key]; }
CDataType& operator[](int index) { return m_Object[index]; }
CDataType* GetAt(LPCTSTR key) { return m_Object.GetAt(key); }
CDataType* GetAt(int index) { return m_Object.GetAt(index); }
void RemoveAll() { return m_Object.RemoveAll(); }
void DeleteAll() { return m_Object.DeleteAll(); }

virtual CString& ToXML(CString& s) {
s.Format("<SETs ID=/"%s/">", Id, m_Object);
return s;
}
};

CCollectionType 是一个可以使用字符名称以及索引查询的CDataType 集合类,由于CCollectionType 是从CDataType 派生,所以CcollectionType 可以被加入到CcollectionType 中,用以形成树状结构。
VC++ 下带有 xml 的解析 IXMLDOMDocument, 虽然没有 C# 下简单,但是在MSXML2 namespace 下的封装类,则相当简单.

bool CXMLFile::Load(LPCTSTR fileName, CCollectionType& collection)
{
try {
if FAILED(::CoInitialize(NULL))
return false;

MSXML2::IXMLDOMDocumentPtr pXMLDoc = NULL;
if FAILED(pXMLDoc.CreateInstance("Msxml2.DOMDocument.4.0"))
return false;
if (! pXMLDoc->load(CComVariant(fileName)))
return false;

MSXML2::IXMLDOMElementPtr pElement = pXMLDoc->documentElement;
if (collection.Id != pElement->nodeName.GetBSTR())
return false;
return ParseObjects(pElement->childNodes, collection);
}
catch (...) { return false; }
}

bool CXMLFile::ParseObjects(MSXML2::IXMLDOMNodeListPtr nodes, CCollectionType& collection)
{
try {
MSXML2::IXMLDOMNodePtr node;
int length = nodes->length;
for (long n=0; n<length; n++) {
node = nodes->item[n];
CString type(node->nodeName.GetBSTR());
if (node->attributes->length < 1) return false;
CComVariant id = node->attributes->item[0]->nodeValue;
if (type == "INT") {
if (node->attributes->length < 2) return false;
CComVariant value = node->attributes->item[1]->nodeValue;
int v = ::atoi((LPCTSTR) CString(value.bstrVal));
collection.Add(CString(id.bstrVal), v);
}
else if (type == "FLOAT") {
if (node->attributes->length < 2) return false;
CComVariant value = node->attributes->item[1]->nodeValue;
float v = (float) ::atof((LPSTR) value.bstrVal);
collection.Add(CString(id.bstrVal), v);
}
else if (type == "INTs") {
if (node->attributes->length < 2) return false;
CIntegerArrayType* v = new CIntegerArrayType;
int cout = node->attributes->length - 1;
for (int i=1; i<node->attributes->length; i++) {
CComVariant value = node->attributes->item[i]->nodeValue;
v->Add(::atoi((LPSTR) value.bstrVal));
}
collection.Add(CString(id.bstrVal), v);
}
else if (type == "STRs") {
if (node->attributes->length < 2) return false;
CStringArrayType* v = new CStringArrayType;
int cout = node->attributes->length - 1;
for (int i=1; i<node->attributes->length; i++) {
CComVariant value = node->attributes->item[i]->nodeValue;
v->Add(CString(value.bstrVal));
}
collection.Add(CString(id.bstrVal), v);
}
else if (type == "STR") {
if (node->attributes->length < 2) return false;
CComVariant value = node->attributes->item[1]->nodeValue;
collection.Add(CString(id.bstrVal), (LPCTSTR) CString(value.bstrVal));
}
else if (type == "SETs") {
CCollectionType* v = new CCollectionType();
collection.Add(CString(id.bstrVal), v);
if (! ParseObjects(node->childNodes, *v))
return false;
}
else {
}
}
}
catch(...) { return false; }
return true;
}

bool CXMLFile::Save(CStdioFile& file, CCollectionType& collection)
{
try {
m_IndentCount = 0;
file.WriteString("<");
file.WriteString(collection.Id);
file.WriteString(">/n");
SaveObjects(file, collection);
file.WriteString("</");
file.WriteString(collection.Id);
file.WriteString(">");
file.Close();
return true;
}
catch (...) { return false; }
}

bool CXMLFile::SaveObjects(CStdioFile& file, CCollectionType& collection)
{
try {
m_IndentCount++;
CString s;
for (int i=0; i<collection.GetCount(); i++) {
CDataType* v= collection.GetAt(i);
for (int n=0; n<m_IndentCount; n++)
file.WriteString(" ");
file.WriteString(v->ToXML(s) + "/n");
if (v->IsCollection()) {
SaveObjects(file, *(CCollectionType*) v);
for (int n=0; n<m_IndentCount; n++)
file.WriteString(" ");
file.WriteString("</SETs>/n");
}
}
m_IndentCount--;
return true;
}
catch (...) { return false; }
}

最终的使用变得非常简单:

CFileDialog openFile(TRUE, NULL, NULL, OFN_HIDEREADONLY,
_T("XML File (*.xml)|*.xml|All Files (*.*)|*.*||"), NULL);

if (openFile.DoModal() == IDOK) {
CXMLFile file;
CCollectionType collection;
collection.Id = _T("DEVICE");
if (! file.Load(openFile.GetFileName(), collection)) {
::MessageBox(NULL, _T(" Cannot open the file for write. "), NULL, MB_ICONSTOP | MB_OK);
return;
}
m_Text.SetWindowText(collection["APPLICATION"]["SYSTEM"]["VERSION"].String());

CString fileName = openFile.GetFileName() + "_";
CStdioFile outfile;
if( !outfile.Open(fileName, CFile::modeCreate|CFile::modeWrite|CFile::typeText)) {
::MessageBox(NULL, _T(" Cannot open the file for write. "), NULL, MB_ICONSTOP | MB_OK);
return;
}
file.Save(outfile, collection);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐