#ifndef my_xmlH
#define my_xmlH
#include <XMLDoc.hpp>
#include <map.h>
#include <vector.h>
//---------------------------------------------------------------------------
class xmlNode; //表征xml节点的类,
//因为与 myXML 有交叉引用,所以在此预先定义一下。
//---------------------------------------------------------------------------
class myXML //xml文件类.
{
private:
int SavePause; //用来控制防止频繁的存盘,提高效率。
private:
AnsiString _fpath; //xml文件名,包含路径。
_di_IXMLDocument XmlDoc; //cb中的xml文档类。
_di_IXMLNode Root; //根节点,只有一个。
public:
myXML(); //构造函数
myXML(AnsiString fpath); //构造函数
void init(AnsiString fpath); //初始化
bool isNull()const; //是否有效
void save()const; //存盘
xmlNode root()const; //获得根节点
void disable_save(); //该函数使后面的save()操作无效。
void enable_save(); //执行save()操作。
//这两个函数总是成对出现,用于使两个函数之间的大量
//零碎的存盘操作(如果有的话)被跳过,以提高系统效率。
//这两个函数是我后来加的,与XML文档没有关系,
//如果你觉得没有必要,可以去掉。
void save_to( AnsiString fpath_ )const; //保存到另外的文件
};
//---------------------------------------------------------------------------
typedef map<AnsiString,AnsiString> attrMap; //用来表示节点的一组属性
//定义这个可以少打好多字。
//---------------------------------------------------------------------------
class xmlNode //表征xml节点的类,
{
private:
_di_IXMLNode _node;
public:
xmlNode();
xmlNode(_di_IXMLNode node);
void init(_di_IXMLNode node);
bool isNull()const;
xmlNode & operator = ( const xmlNode & node_ );
public:
AnsiString name()const; //返回节点的名字。
AnsiString attribute(AnsiString name)const;
//返回一个属性值。name表示属性名称。
AnsiString value()const; //获得该节点的字符串值。
AnsiString child_value(AnsiString name)const;
//返回该节点的一个子节点的值。name是子节点的节点名字。
void set_value( AnsiString value_ )const; //设置本节点的值。
void set_attribute(AnsiString name,AnsiString value)const;
//设置本节点的一个属性值。形如:name="value"
void set_child_value(AnsiString name,AnsiString value)const;
//设置本节点的一个子节点的值。形如:<name>value<name/>
xmlNode find_child_node(AnsiString name)const;
//返回名字是name的子节点,如果有的话。
xmlNode get_child_node(AnsiString name)const;
//返回一个名字是name的子节点,如果没有,创建一个。
void get_attrs( map<AnsiString,AnsiString> & attrs )const ;
//一次获得本节点所有的属性。
void set_attrs( const map<AnsiString,AnsiString> & attrs )const ;
//先将旧的属性全部删除,新属性作为一个整体增加。
void find_child_nodes(vector<xmlNode> & nodes)const; //获得所有子节点。
void del_child_nodes()const; //删除所有子节点。
void add_child_node( AnsiString child_name )const; //增加一个子节点
void del_child_node( AnsiString child_name )const; //删除一个子节点。
};
//---------------------------------------------------------------------------
#endif
//下面是"my_xml.cpp"的内容:
//---------------------------------------------------------------------------
#pragma hdrstop
#include "my_xml.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//--------------------------------------------------------------------------
//-----------------------------------------------------------------------
myXML::myXML():XmlDoc(NULL),Root(NULL),SavePause(0)
{
}
//-----------------------------------------------------------------------
myXML::myXML(AnsiString fpath) : XmlDoc(NULL),Root(NULL),SavePause(0)
{
init(fpath);
}
//-----------------------------------------------------------------------
void myXML::init(AnsiString fpath)
{
_fpath = fpath;
if( NULL != XmlDoc )delete XmlDoc; //我对这行代码没有信心,还请高人指点。
XmlDoc = NULL;
if( fpath.Length() == 0 )
{
}
else
{
if(FileExists(fpath)) //如果文件存在
{
try{ XmlDoc = LoadXMLDocument(fpath);}
catch(...){ XmlDoc = NULL;}
}
else //如果文件不存在,
{
try{ XmlDoc = NewXMLDocument(L"1.0"); } //创建, L""表示宽字符串。
catch(...){ XmlDoc = NULL;}
if( NULL == XmlDoc ){}
else XmlDoc->FileName = fpath;
}
}
if(XmlDoc == NULL){ Root = NULL; }
else
{
XmlDoc->Encoding = AnsiString("UTF-16");
//编码方式还可以选择:
//"gb2312" 与一般中文文本兼容
//"utf-8" 适于全部是英文的情况。
//"big5" 台湾繁体中文
Root = XmlDoc->DocumentElement;
if( Root == NULL )
{
XmlDoc->AddChild("root"); //根节点,必须有一个。一般用"root"
Root = XmlDoc->DocumentElement;
}
}
SavePause = 0;
}
//---------------------------------------------------------------------
bool myXML :: isNull()const{ return (Root == NULL); }
//---------------------------------------------------------------------
void myXML :: save()const //存盘
{
if( Root == NULL )return;
if( SavePause > 0 )return;
if( _fpath.Length() == 0 )return;
if( XmlDoc->Modified )
{
try{ XmlDoc->SaveToFile( _fpath ); }catch(...){}
}
}
//---------------------------------------------------------------------
xmlNode myXML :: root()const{ return xmlNode(Root);}
//---------------------------------------------------------------------
void myXML :: disable_save(){ ++SavePause; }
//---------------------------------------------------------------------
void myXML :: enable_save(){ --SavePause; save(); }
//---------------------------------------------------------------------
void myXML::save_to( AnsiString fpath_ )const //保存到...
{
if( Root == NULL )return;
try{ XmlDoc->SaveToFile( fpath_ ); }catch(...){}
}
//---------------------------------------------------------------------
//===========================================================================
//---------------------------------------------------------------------
//本函数用于替换掉字符串中含有的非法字符,防止其写入xml文件中。
//这里简单的用空格替换,不一定合适。有待大家指正。
static AnsiString & Valid(AnsiString & str)
{
const int Len = str.Length();
for(int i=1;i<=Len;++i)
{
char & c = str[i]; if(c > 0x00 && c < 0x20)c = ' ';
}
return str;
}
//-----------------------------------------------------------------------
xmlNode :: xmlNode(){ _node = NULL; }
//-----------------------------------------------------------------------
xmlNode :: xmlNode(_di_IXMLNode node){ _node = node;}
//-----------------------------------------------------------------------
void xmlNode :: init(_di_IXMLNode node){ _node = node;}
//-----------------------------------------------------------------------
bool xmlNode :: isNull()const{ return (_node == NULL); }
//-----------------------------------------------------------------------
xmlNode & xmlNode::operator = ( const xmlNode & node_ )
{
_node = node_._node; return *this;
}
//-----------------------------------------------------------------------
//返回一个名字是name的子节点,如果没有,创建一个。
xmlNode xmlNode :: get_child_node(AnsiString name)const
{
if(_node == NULL)return xmlNode(NULL);
_di_IXMLNode node = _node->ChildNodes->FindNode(name);
if(node == NULL)
{
return xmlNode(_node->AddChild(name));
}
else return xmlNode(node);
}
//-----------------------------------------------------------------------
//返回名字是name的子节点。
xmlNode xmlNode :: find_child_node(AnsiString name)const
{
if(_node == NULL)return xmlNode(NULL);
return xmlNode(_node->ChildNodes->FindNode(name));
}
//-----------------------------------------------------------------------
AnsiString xmlNode :: name()const
{
if(_node == NULL)return AnsiString();
return _node->NodeName;
}
//-----------------------------------------------------------------------
AnsiString xmlNode :: value()const //获得该节点的字符串值。
{
if(_node == NULL)return AnsiString();
AnsiString S;
try
{
OleVariant v = _node->Text;
if(v.IsNull())S = AnsiString();
else S = AnsiString(v);
}
catch(...){ S = AnsiString();}
return S;
}
//-----------------------------------------------------------------------
AnsiString xmlNode :: child_value(AnsiString name)const //返回子节点的值。
{
if(_node == NULL)return AnsiString();
AnsiString S;
try
{
OleVariant v = _node->ChildValues[name];
if(v.IsNull())S = AnsiString();
else S = AnsiString(v);
}
catch(...){ S = AnsiString();}
return S;
}
//-----------------------------------------------------------------------
void xmlNode::set_value( AnsiString value_ )const
{
if(_node == NULL)return; Valid( value_ );
try{ _node->Text = value_; }catch(...){}
}
//-----------------------------------------------------------------------
void xmlNode :: set_child_value(AnsiString name,AnsiString value)const
{
if(_node == NULL)return ;
Valid(value);
const _di_IXMLNode node = _node->ChildNodes->FindNode(name);
if(node == NULL)
{
if(value.Length() == 0);
else
{
try{ _node->AddChild(name)->Text = value;}catch(...){}
}
}
else
{
if(value.Length() == 0)
{
try{ _node->ChildNodes->Remove(node);}catch(...){}
}
else
{
try{ _node->ChildValues[name] = value;}catch(...){}
}
}
}
//-----------------------------------------------------------------------
AnsiString xmlNode :: attribute(AnsiString name)const
{
if(_node == NULL)return AnsiString();
AnsiString S;
try{
OleVariant v = _node->Attributes[name];
if(v.IsNull())S = AnsiString();
else S = AnsiString(v);
}
catch(...){ S = AnsiString();}
return S;
}
//-----------------------------------------------------------------------
void xmlNode :: set_attribute(AnsiString name,AnsiString value)const
{
if(_node == NULL)return ;
Valid(value);
if(value.Length() == 0)
{
try{ _node->Attributes[name] = Null();}catch(...){}
}
else
{
try{ _node->Attributes[name] = value;}catch(...){}
}
}
//-----------------------------------------------------------------------
void xmlNode :: find_child_nodes(vector<xmlNode> & nodes)const
{
if(_node == NULL)return ;
_di_IXMLNodeList List = _node->ChildNodes;
for(int i=0;i<List->Count;i++)
{
if( List->Nodes[i]->NodeType == ntElement )
{
nodes.push_back(List->Nodes[i]);
}
}
}
//-----------------------------------------------------------------------
//一次获得本节点所有的属性。
void xmlNode :: get_attrs(map<AnsiString,AnsiString> & attrs)const
{
if(_node == NULL)return ;
_di_IXMLNodeList List = _node->AttributeNodes ;
for(int i=0;i<List->Count;i++)
{
AnsiString attr_name = List->Nodes[i]->NodeName;
AnsiString attr_value;
try{ attr_value = List->Nodes[i]->NodeValue; }
catch(...){ attr_value = AnsiString(); }
attrs.insert(make_pair(attr_name,attr_value));
}
}
//-----------------------------------------------------------------------
//先将旧的属性全部删除,新属性作为一个整体增加。
void xmlNode :: set_attrs(const map<AnsiString,AnsiString> & attrs)const
{
if(_node == NULL)return ;
_node->AttributeNodes->Clear();
map<AnsiString,AnsiString>::const_iterator p;
for( p = attrs.begin(); p != attrs.end(); ++p )
{
set_attribute(p->first,p->second);
}
}
//-----------------------------------------------------------------------
void xmlNode :: add_child_node(AnsiString child_name)const
{
if(_node == NULL)return ;
_node->AddChild(child_name);
}
//-----------------------------------------------------------------------
void xmlNode :: del_child_nodes()const
{
if(_node == NULL)return ;
if(_node->HasChildNodes)
{
_node->ChildNodes->Clear();
}
}
//-----------------------------------------------------------------------
void xmlNode :: del_child_node(AnsiString child_name)const
{
if(_node == NULL)return ;
if(_node->HasChildNodes)
{
_node->ChildNodes->Delete( child_name );
}
}
//-----------------------------------------------------------------------
//因为代码不是一次写成的,所以有点乱。
//---------------------------------------------------------------------
//=========================== END =========================================
//应用举例:下面的函数生成一个这样的XML文件。
<?xml version="1.0" encoding="UTF-16"?>
<root>
<成绩单 语文="98" 数学="108" 英语="88"/>
<体重>67</体重>
<身长>180</身长>
</root>
//------------------------------------------
void func()
{
myXML xml;
xml.init("d://1.xml");
xmlNode root = xml.root();
xmlNode node = root.get_child_node("成绩单");
node.set_attribute("语文","98");
node.set_attribute("数学","108");
node.set_attribute("英语","88");
node = root.get_child_node("体重");
node.set_value("67");
root.set_child_value("身长","180");
xml.save();
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
注意事项:
1,Build 以前,必须在程序中的某个Form上放一个 XMLDocument 控件(在Internet页),
然后完全编译(Project->Options->Linker->Use Dynamic RTL,Project->Options->
Packages->Build with runtime packages,两个对勾去掉),编译完成后,删掉这个
XMLDocument 控件即可。
2,由于此处myXML的初始化依赖于程序底层的XML解析器,而解析器的初始化是在程序启动后
完成的(在WinMain函数启动后),所以 myXML(AnsiString)构造函数和myXML.init()函数
不能在 WinMain()前被调用。啰嗦这些只有一个意思,就是:
你不能这样定义一个全局的xml变量:
myXML xml("d://test//tt.xml"); //这种情况下xml不能正确初始化。
//---------------------------------------------------------------------