最近做项目需要用c++解析xml文件,在c#下用5分钟搞定的活我整整扣了2天。
c++中解析xml文件的方法有很多,我选择Xerces -C++,主要是开源,也比较好用,但是由于以前没有接触过,也费了一番心思,废话不多说,进入正题。
http://www.yolinux.com/TUTORIALS/XML-Xerces-C.html linux中的安装使用
http://xerces.apache.org/xerces-c/apiDocs-3/index.html 官网的连接,其中有类和函数接口说明
下载安装,参考网上其他链接
主要介绍解析xml
XMLPlatformUtils::Initialize(); 初始化平台,可以写在构造方法中 ,使用前必须初始化
XMLPlatformUtils::Terminate();销毁平台 ,可以修在析构方法中。
//加载文件 filePath 为xml文件路径 (同样可以加载字符串形式的xml,参考中间部分读取cdata 内部 xml字段)
XercesDOMParser *m_DOMXmlParser = new XercesDOMParser();
m_DOMXmlParser->parse(filePath.GetBuffer(0));
//得到文件对象
DOMDocument *xmlDoc = m_DOMXmlParser->getDocument();
//根节点为空
if(!xmlDoc->getDocumentElement()) //getDocumentElement用来得到文件根节点
{
delete(m_DOMXmlParser);
m_DOMXmlParser = NULL;
return false;
}
//得到code 节点 当对应多个 code节点时 则是 nodelist 可用循环遍历,这里只有一个code 就去 item(0)的值 getElementsByTagName 方法很好
DOMNode* xCode = xmlDoc->getElementsByTagName(XMLString::transcode("CODE"))->item(0);
//取得属性的名称 TEXT
char *bb = XMLString::transcode(xCode->getAttributes()->item(0)->getNodeName());
//得到属性的值 (每个节点的第一个子节点都是它的值,即便这个值为空,当当前节点是TEXT_NODE属性时 ,才能得到getNodeValue的值) 这是取TEXT 属性的值,取结点的值 方法相同
char* aa = XMLString::transcode(xCode->getAttributes()->item(0)->getFirstChild()->getNodeValue());
//第二个 属性
char *cc = XMLString::transcode(xCode->getAttributes()->item(1)->getNodeName());
char* dd = XMLString::transcode(xCode->getAttributes()->item(1)->getFirstChild()->getNodeValue());
//读取state节点值
DOMNode *xState = xmlDoc->getElementsByTagName(XMLString::transcode("STATE"))->item(0);//同样只有一个节点,直接区0
string str_name = XMLString::transcode(xState->getNodeName()); //可以用来取节点名称
string str_state = XMLString::transcode(xState->getFirstChild()->getNodeValue());//XMLString::transcode 用于字符转换 XMLch转为 string 或者 char*
//下面准备去cdata 部分的内容
//找到data节点 cdata 看做是 data的子节点
DOMNode* xData = xmlDoc->getElementsByTagName(XMLString::transcode("DATA"))->item(0);
DOMNodeList* nodeList = xData->getChildNodes();//data节点的子节点 集合
unsigned int len = nodeList->getLength();
//遍历子节点的结合
for (unsigned int i = 0;i<len;i++)
{
DOMNode *tmpNode = nodeList->item(i);//遍历节点
if(tmpNode->getNodeType() == DOMNode:: CDATA_SECTION_NODE ) //cdata的类型CDATA_SECTION_NODE 其他的 节点 或者 内容都有自己的类型关键字 ,参照官网
{
DOMCDATASection *cdata = (DOMCDATASection*)tmpNode;
//加入报文头,不然无法解析
CString cdata_innerStr = "<?xml version=\"1.0\" encoding=\"GBK\"?>";
CString temp11.Format("%s",XMLString::transcode(cdata->getData()));//getData()得到cdata 内部字符窜
cdata_innerStr += temp11;
//通过类型转换
MemBufInputSource mem((const unsigned char*)cdata_innerStr.GetBuffer(cdata_innerStr.GetLength()),cdata_innerStr.GetLength(),(const XMLCh*)0);
//mem 是字符窜,这里就是加载字符串型是的xml文件,下面的解析方法与上面相同了
//加载cdata内部 xml文件
XercesDOMParser *m_parser = new XercesDOMParser();
m_parser->parse(mem);
DOMDocument* cdoc = m_parser->getDocument();
DOMNode* xKp = cdoc->getElementsByTagName(XMLString::transcode("KP"))->item(0);
CString str_kp;
str_kp.Format("%s",XMLString::transcode(xKp->getFirstChild()->getNodeValue()));
if (str_kp != "1")
{
//读取 cdata中的msg节点
DOMNode* xd_Msg = cdoc->getElementsByTagName(XMLString::transcode("MSG"))->item(0);
msg.Format("%s",XMLString::transcode(xd_Msg->getFirstChild()->getNodeValue()));
delete(m_DOMXmlParser);
m_DOMXmlParser = NULL;
return false;
}
}
}
delete(m_DOMXmlParser);
m_DOMXmlParser = NULL;
<?xml version="1.0" encoding="GBK" ?>
<NS>
<CODE TEST="456" VALUE="789">123</CODE>
<RSPTIME>abc</RSPTIME>
<STATE>1</STATE>
<MSG>edg</MSG>
<DATA>
<![CDATA[
<ROOT>
<N NAME="mingcheng" VALUE="TEST"/>
<KP>0</KP>
<MSG>wufakaipiaoyuanyin</MSG>
</ROOT>
]]>
</DATA>
</NS>
以上代码 ,亲身测试过