现在
,
越来越多的程序使用
xml
文件作为应用程序的配置文件
,
在
windows
平台上
,
一般的程序使用微软的
msxml
接口来读写
xml
文件
.
xml
文件原则上可以存储任意形式的数据
,
比如象点坐标
,
颜色
rgb
值
,
矩形坐标
,
字符串
,
数值或者其他自己定义的数据结构等
.
如果
xml
需要存储结构化的数据列
,
或者存储在
xml
文件中的数据因为逻辑或者业务的原因存在结构上的嵌套包含关系
,
比如要存储某个窗口的位置
,
标题
,
坐标等情况
,
还要存储这个窗口的子窗口的相同信息
.
在情况下
,
会存在下列几个问题
1.
应用程序配置结构和
xml
读写操作过于耦合
,
如果要将不同的结构写入
xml
文件
,
需要操作
msxml
调用不同的接口
,
而一旦这些配置结构发生改变
,
将需要同时修改
xml
文件的读写代码
.
对于不同的配置结构
,
就需要写不同的
xml
读写操作
,
代码重用性不高
.
2.
对于多个数据对象和有嵌套包含关系的数据结构而言
,
还需要自己实现循环语句对
xml
文件中的对象进行读写
.
本文实现了一个
xml
读写和自身结构无关的类模板
,
并且支持结构嵌套
,
简化了
xml
的读写操作
,
需要
Loki for vc6
库支持
.
如想要存储一组
web
站点的结构
,
包括
url(string),
端口
(int),
用户名
(string),
口令
(string)
可以定义下面的类结构
:
class
__app_config
:
public
Xml_Attribute_List
<TYPELIST_1(
XML_ATTR_NULLTYPE
)>
{
public
:
__app_config
() {
SetTagName
(
_T
(
"AppConfig"
));
}
~
__app_config
() {}
};
typedef
Xml_Config_Node
<
__app_config
>
AppConfigRoot
;
class
__site_info
:
public
Xml_Attribute_List
<TYPELIST_4(
XML_ATTR_CSTRING
,
XML_ATTR_INT
,
XML_ATTR_CSTRING
,
XML_ATTR_CSTRING
)>
{
public
:
__site_info
() {
SetTagName
(
_T
(
"WebSite"
));
SetAttributeName
(
_T
(
"url"
),
_T
(
"port"
),
_T
(
"username"
),
_T
(
"password"
));
}
~
__site_info
() {}
GET_SET_ATTR4
(
url
,
port
,username,password, TYPELIST_4(
XML_ATTR_CSTRING
,
XML_ATTR_INT
,
XML_ATTR_CSTRING
,
XML_ATTR_CSTRING
))
};
typedef
Xml_Config_Node
<
__site_info
>
WebSiteInfoNode
;
typedef
XmlConfigNodeFactory
<TYPELIST_2(
AppConfigRoot
,
WebSiteInfoNode
)>
NodeCreateFactory
;
typedef
XmlConfigFile
<
AppConfigRoot
,
NodeCreateFactory
>
AppConfigFileBase
;
class
AppConfigFile
:
public
AppConfigFileBase
{
public
:
void
AddSiteInfo
(
LPCTSTR
url
,
int
port
,
LPCTSTR
user
,
LPCTSTR
pwd
) {
WebSiteInfoNode
*
pnode
=
new
WebSiteInfoNode
;
pnode
->
GetAttribute
().Set_url(
url
);
pnode
->
GetAttribute
().
Set_port
(
port
);
pnode
->
GetAttribute
().
Set_username
(
user
);
pnode
->
GetAttribute
().
Set_password
(
pwd
);
GetRoot
().
AddChildNode
(
pnode
);
}
int
GetSiteInfoCount
() {
return
GetRoot
().
GetChildCount
();
}
WebSiteInfoNode
*
GetSiteInfo
(
int
index
) {
Xml_NodeData_Base
*
pbase
=
GetRoot
().
GetChildNode
(
index
);
if
(
pbase
) {
WebSiteInfoNode
*
pnode
= (
WebSiteInfoNode
*)
pbase
;
return
pnode
;
}
else
{
return
NULL
;
}
}
public
:
AppConfigFile
() {}
~
AppConfigFile
() {}
};
配置信息存储和加载的代码
void
SaveConfig
()
{
AppConfigFile
lconfigfile
;
lconfigfile
.
AddSiteInfo
(
"192.168.0.1"
,
80
,
"guest"
,
"hello"
);
lconfigfile
.
AddSiteInfo
(
"192.168.0.2"
,
80
,
"guest"
,
"hello"
);
lconfigfile
.
AddSiteInfo
(
"192.168.0.3"
,
80
,
"guest"
,
"hello"
);
lconfigfile
.
AddSiteInfo
(
"192.168.0.4"
,
80
,
"test"
,
"hi"
);
lconfigfile
.
SaveToXmlFile
(
"c:\\test.xml"
);
}
void
output_config
(
WebSiteInfoNode
*
pnode
)
{
if
(
pnode
) {
cout
<< (
LPCTSTR
)
pnode
->
GetAttribute
().Get_url() <<
" "
;
cout
<<
pnode
->
GetAttribute
().
Get_port
() <<
" "
;
cout
<< (
LPCTSTR
)
pnode
->
GetAttribute
().
Get_username
() <<
" "
;
cout
<< (
LPCTSTR
)
pnode
->
GetAttribute
().
Get_password
() <<
endl
;
}
}
void
LoadConfig
()
{
AppConfigFile
lconfigfile
;
lconfigfile
.
LoadFromXmlFile
(
"c:\\test.xml"
);
int
i
,
count
;
count
=
lconfigfile
.
GetSiteInfoCount
();
if
(
count
>
0
) {
for
(
i
=
0
;
i
<
count
;
i
++) {
WebSiteInfoNode
*
pnode
=
lconfigfile
.
GetSiteInfo
(
i
);
output_config
(
pnode
);
}
}
}
可以看见,在代码中,没有具体的有关xml文件的读写操作的,涉及的只是于业务相关的数据结构的定义和存取操作,同时,在业务需求发生变化或者需要添加新的业务结构时,只需要修改业务结构定义和定义新的业务结构并将其加入节点创建工厂就可以了.
代码下载
http://www.cppblog.com/Files/hdqqq/xml_config_file.rar
附加说明
:
代码中使用抽象工厂作来创建节点对象
,
对于存储于
xml
文件中的结构
,
采用
md5
的
hash
值作为每个结构的
id.