最近,项目组让搞一个读取xml配置文件的数据库连接信息的功能。
一开始准备使用tinyxml,或者rapidxml。没注意delta3d的读取xml信息的类。
后来发现,delta3d中读取xml的类,是对xecres的一些二次封装,专门读delta3d的地图,里面含有角色代理之类的。
对于读取自己的数据库连接信息不太方便。就准备用delta3d自带的xecres开源库,自己写一个。
一开始以为xecres的资料应该很多,后来发现都不太完整,结合网上的一些实例。搞了二天,终于出了一版读取自己xml的一个类。
写下来,以便记忆。如后来有改善,就不断更新。
代码如下:头文件:
#include <xercesc/dom/DOMDocumentType.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMImplementationLS.hpp>
#include <xercesc/dom/DOMNodeIterator.hpp>
#include <xercesc/dom/DOMNodeList.hpp>
#include <xercesc/dom/DOMNamedNodeMap.hpp>
#include <xercesc/dom/DOMText.hpp>
#include <xercesc/dom/DOMAttr.hpp>
#include <xercesc/dom/DOMTreeWalker.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/framework/XMLFormatter.hpp>
#include <xercesc/util/XMLString.hpp>
#include <stdlib.h>
#include <string>
#include <vector>
#include <map>
#include <stdexcept>
using namespace std;
using namespace xercesc;
class ReadXml
{
public:
ReadXml();
~ReadXml();
void xmlParser(string&) throw(std::runtime_error);
int loopXMLElement(DOMNode *node);
private:
XercesDOMParser *m_DOMXmlParser;
typedef map<string ,string> DATA_INFORMATION;
DATA_INFORMATION dataMap;
};
实现文件:
#include <string>
#include <iostream>
#include <sstream>
#include "ReadXML.h"
ReadXml::ReadXml()
{
try
{
XMLPlatformUtils::Initialize();//初始化类库
}
catch (xercesc::XMLException& excp)
{
char* msg = XMLString::transcode(excp.getMessage());
printf("XML tookit initialization error: %S\n",msg);
XMLString::release(&msg);
}
m_DOMXmlParser = new XercesDOMParser;
}
ReadXml::~ReadXml()
{
try
{
XMLPlatformUtils::Terminate();
}
catch(XMLException& excp)
{
char* msg = XMLString::transcode(excp.getMessage());
printf("XML toolkit terminate error: %s\n", msg);
XMLString::release(&msg);
}
}
void ReadXml::xmlParser(string& xmlFile) throw(std::runtime_error)
{
m_DOMXmlParser->setValidationScheme(XercesDOMParser::Val_Auto);//采用Schemal自动验证
/*设置Parser是否处理xml文档中的名域,如果为true,则Parser增强名域定义的约束和规则。*/
m_DOMXmlParser->setDoNamespaces( false );
/*设置Parser处理xml文档中的schema,false就是不处理 */
m_DOMXmlParser->setDoSchema( false );
/**/
m_DOMXmlParser->setLoadExternalDTD( false );
try
{
/*Parser解析器调用parse方法解析XML,安装解析器设置的各种参数,执行Schemal验证,将XML读取到内存,并成为一个DOM树形结构*/
m_DOMXmlParser->parse(xmlFile.c_str()) ;
//取得DOM数据
DOMDocument* xmlDoc = m_DOMXmlParser->getDocument();
//取得根结点
DOMElement *pRoot = xmlDoc->getDocumentElement();
if (!pRoot )
{
throw(std::runtime_error( "empty XML document" ));
}
//创建一个 walker to 遍历结点
//DOMNodeFilter::SHOW_ELEMENT显示元素结点,SHOW_TEXT显示文本结点
DOMTreeWalker* walker = xmlDoc->createTreeWalker(pRoot,DOMNodeFilter::SHOW_ELEMENT,0,true);
std::cout<<"TreeWalker:\n";
for (DOMNode *current = walker->nextNode();current!=0;current=walker->nextNode())
{
loopXMLElement(current);
}
std::cout<<std::endl;
//创建一个迭代器去遍历结点
DOMNodeIterator* iterator = xmlDoc->createNodeIterator(pRoot,
DOMNodeFilter::SHOW_ELEMENT, NULL, true);
std::cout<< "iterator遍历开始:\n";
for ( DOMNode * current = iterator->nextNode();
current != 0; current = iterator->nextNode() )
{
string strName = XMLString::transcode(current->getNodeName());
string strValue = XMLString::transcode((current->getFirstChild())->getNodeValue());
std::cout <<strName<<strValue<<endl;
}
std::cout<< std::endl;
}
catch( xercesc::XMLException& excp )
{
char* msg = xercesc::XMLString::transcode( excp.getMessage() );
ostringstream errBuf;
errBuf << "Error parsing file: " << msg << flush;
XMLString::release( &msg );
}
}
/**@brief 遍历DOM节点,采用递归算法,遍历该节点下的所有元素极其属性值(该方法主要是用于上面的parse方法的调用)
* @param 需要遍历的节点
* @return 0:表示遍历成功,1:表示失败
*/
int ReadXml::loopXMLElement(DOMNode *node)
{
//DOMNode * child;
if (node->getNodeType() == DOMNode::ELEMENT_NODE) {
/*XMLString.transcode() 这个方法有多个重载,既可以把 XMLCh * 格式的数据转换成
char *的数据,也可以把 char * 的数据转换成 XMLCh *, 我们也可以利用这个函数来
初始化 XMLCh格式类型的数组,比如 XMLCh temp[100];
XMLString.transcode(“LS”,temp,99);
用“ LS ”初始化 temp 这个数组的内容。*/
//char * nodeName = XMLString::transcode(node->getNodeName());//获取该节点的名称,这里不需要,注释掉
//std::string strName(nodeName);
//获取改节点的属性值,作为map中的value
char * nodeValue = XMLString::transcode((node->getFirstChild())->getNodeValue());
std::string strValue(nodeValue);
//如果该节点下有属性,则遍历其属性
if (node->hasAttributes())
{
DOMNamedNodeMap *pAttributes = node->getAttributes();
const XMLSize_t nSize = pAttributes->getLength();
//遍历该节点下的所有属性
for (XMLSize_t i = 0; i < nSize; ++i)
{
DOMAttr *pAttributeNode = (DOMAttr*) pAttributes->item(i);
/* 属性的名字不需要
char *name = XMLString::transcode(pAttributeNode->getName());
std::string name_str = name;*/
//获取属性值,作为map中的key
char *attrValue = XMLString::transcode(pAttributeNode->getValue());
string attr_str = attrValue;
//将属性值存放到返回的对象中,此处自己构造对象填值
std::cout<<attrValue<<"="<<strValue<<std::endl;
/*本map就是用来存储用户登录数据库信息形式如下:
hostname":192.168.131.202*/
dataMap[attrValue]=strValue;
XMLString::release(&attrValue);//释放资源
}
}
XMLString::release(&nodeValue);
}
return 0;
}
int main(int argc ,char* argv[])
{
ReadXml *xx = new ReadXml();
string ss = "dbconfig.xml";//添加自己的配置文件。
xx->xmlParser(ss);
return 0;
}
以上代码,放在VS中,可以直接运行。如有改善,请跟评论,谢谢。
我的配置文件是如下格式:
<dbconfig>
<property name="hostname">192.168.131.202</property>
<property name="databasename">*****</property>
<property name="username">****</property>
<property name="password">****</property>
<property name="port">***</property>
</dbconfig>