最近做项目需要用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>



以上代码 ,亲身测试过