zoukankan      html  css  js  c++  java
  • tiny xml 使用总结

    这几天在埋头写自己的3D文件浏览器(稍后发布),突发奇想的要把自己的内部格式转化成XML,于是,把以前在研究所时用过的ExPat翻了出来。ExPat是基于事件的XML解释器,速度挺快的,但结构方面有点不敢恭维--当年写配置文件的导出导入部分花了我足足1个星期!而且由于它是基于事件发生的次序(SAX),似乎有时会发生一些无法控制的情况--例如进入某Level后忘了记录,结果……后面的程序全部死掉!这时想起同事之前推荐的TinyXML,结果……用了不到3小时就把我的文件导出来了~~呵呵。在阅读本文之前,请先看看我Blog里转贴的《TinyXML学习笔记》,相信它能给各位一个关于TinyXML的初步概念。

     

    言归正传,本文目的在于补全之前《TinyXML学习》的不足,尽量把常用的示例代码列出让大家参考。此外,在本篇最后会给出一个完整的文件读写例子,供读者参考。

     

    1. 编程环境的设置。新建一个项目,起名叫TestTXML。到http://sourceforge.net/projects/tinyxml/ 下载TinyXML的官方例子,并编译第一个Project tinyxml(注意,最好编译Release的版本,代码比较小。然后把生成的tinyxml.lib(如果是Debug版本,叫tinyxmld.lib)连同tinystr.h和tinyxml.h一起Copy到TestTXML项目的目录中。在TestTXML项目里的头文件加入对TinyXML的引用:

    #pragma comment(lib,"tinyxml.lib") // 链接Library

    #include "tinyxml.h" // TinyXML的头文件

     

    2. 建立一个XML文件:

    char* sFilePath = "ikk_doc.xml"; // 文件名称

    TiXmlDocument xmlDoc( sFilePath ); // 建立一个XML文件

    TiXmlDeclaration Declaration( "1.0","gb2312", "yes" ); // 声明XML的属性

    xmlDoc.InsertEndChild( Declaration ); // 写入基本的XML头结构

    xmlDoc.SaveFile(); // 把XML文件写入硬盘

    这时,在硬盘上的TestXML项目目录里,ikk_doc.xml文件已经被创建出来了。

     

    3. 在XML文件里插入Element

    所谓的Element,就是在XML里面的Tag,例如在<resume name=”裕作”>简历内容</resume>中,“Resume”就是Element的名字,上述的整个字符串就是一个Element。在TinyXML里,插入Element的步骤如下:

    TiXmlElement* pElm = NULL;

    pElm = new TiXmlElement( "resumes" ); //定义当前的子节点 pElmParent.InsertEndChild( *pElm ); // 把子节点插入父节点中

    4. 在element里插入属性。在刚才例子中,name=”裕作”就是Resume的属性,其中name是属性的名字,”裕作”是属性的值。在当前子节点内插入属性的方法如下:

    pElm->SetAttribute( "name", resume.sName );

     

    5. 在XML里插入文本。在<resume name=”裕作”>简历内容</resume>中,“简历内容”就是一段文本,事实上,在TinyXML里,它是被当作一个Text类型的子节点来插入的。还而言之,就是在Resume的子节点中,插入这个Text子节点。插入例子如下:

    TiXmlText* pText = NULL; 
    pText = new TiXmlText( "简历内容" ); // 定义文本的内容

    pElmChild->InsertEndChild( *pText ); //把text子节点插入父节点中

     

    在具备了以上背景知识之后,我们已经可以用TinyXML读写一个XML文件了。本文最后的程序将写入,然后重新读取一个XML文件到我们的结构里。这个XML文件的内容如下:

     

    <?xml version="1.0" encoding="GB2312" ?>

    <resumes>

        <resume name="裕作">

           <gender>男</gender>

           <age>26</age>

           <skills num="2">

               <skill level="99">编程</skill>

               <skill level="1">吹牛</skill>

           </skills>

        </resume>

        <resume name="裕作 The Great">

            <gender>男</gender>

            <age>0</age>

            <skills num="1">

                <skill level="100">编程</skill>

            </skills>

        </resume>

    </resumes>

     

     

     

    以下程序将建立ikk_doc.xml文件,然后重新把内容读取进内存:

     

    #pragma comment(lib,"tinyxml.lib")

     

    #include "string.h"

    #include "stdio.h"

    #include "tinyxml.h"

     

    #define XML_FILE "ikk_doc.xml"

    #define NAME_LENGTH 256 // 名字类字符的分配长度

    #define SAFE_DELETE(x) {if(x) delete x; x=NULL;} // 安全删除new分配出来的变量空间

    #define SAFE_DELETE_ARRAY(x) {if(x) delete[] x; x=NULL;} // 安全删除new分配出来的数组空间

    #define XML_HEADER "<?xml version="1.0" encoding="GB2312" ?>" // XML文件头的定义

     

    typedef unsigned int uint32;

     

    // 技能的结构

    typedef struct skill_s {

        uint32 nLevel; // 技能的程度

        char sName[ NAME_LENGTH ]; // 技能的名称

     

        skill_s() {

            nLevel = 0;

            sName[0] = 0;

        }

    } skill_t;

     

    // 简历的结构

    typedef struct resume_s {

        char sName[ NAME_LENGTH ]; // 名字

        bool isMan; // 是否男性

        uint32 nAge; // 年龄

        uint32 nNumSkill; // 技能的数目

        skill_t* pSkill; // 技能的结构

     

        resume_s() {

            sName[0] = 0;

            isMan = false;

            nAge = 0;

            nNumSkill = 0;

            pSkill = NULL;

        }

    } resume_t;

     

    void exportSkill( TiXmlElement* pElmParent, skill_t skill )

    {

        int i;

        char sBuf[NAME_LENGTH]; // 一个临时存放的字符串

        TiXmlElement* pElm = NULL; // 一个指向Element的指针

        TiXmlText* pText = NULL; // 一个指向Text的指针

        pElm = new TiXmlElement( "skill" );

     

        // 插入等级(以属性形式)

        sprintf( sBuf, "%d", skill.nLevel ); // 把Skill的登记变成字符串临时存进sBuf里

        pElm->SetAttribute( "level", sBuf ); // 把等级插入Skill里

     

        // 插入技能名称(以子Element形式)

        pText = new TiXmlText( skill.sName ); // 建立一个Skill的子Element(一个Text形式的子元素)

        pElm->InsertEndChild( *pText ); // 把这个Skill的子Element插入Skill里

        SAFE_DELETE( pText ); // 删除这个Text

     

        // 最后把整个Resume的子节点插入到父节点中

        pElmParent->InsertEndChild( *pElm );

    }

     

    void importSkill( TiXmlElement* pElm, skill_t* pSkill )

    {

        int i;

        char sBuf[NAME_LENGTH]; // 一个临时存放的字符串

        TiXmlElement* pElmChild = NULL; // 一个指向Element的指针

        TiXmlText* pText = NULL; // 一个指向Text的指针

        // 读取level

        pSkill->nLevel = atoi( pElm->Attribute( "level" ) );

        // 读取技能名称

        strcpy( pSkill->sName, pElm->FirstChild()->Value() );

    }

     

    void exportResume( TiXmlElement* pElmParent, resume_t resume )

    {

        int i;

        char sBuf[NAME_LENGTH]; // 一个临时存放的字符串

        TiXmlElement* pElm = NULL; // 一个指向Element的指针

        TiXmlElement* pElmChild = NULL; // 一个指向Element的指针

        TiXmlText* pText = NULL; // 一个指向Text的指针

        pElm = new TiXmlElement( "resume" );

     

        // 插入名字(以属性形式)

        pElm->SetAttribute( "name", resume.sName );

     

        // 插入性别(以子Element形式)

        pElmChild = new TiXmlElement( "gender" ); // 建立一个子Element叫Gender

        if( resume.isMan )

            pText = new TiXmlText( "男" ); // 建立一个Gender的子Element(一个Text形式的子元素)

        else

            pText = new TiXmlText( "女" ); // 建立一个Gender的子Element(一个Text形式的子元素)

        pElmChild->InsertEndChild( *pText ); // 把这个Gender的子Element插入Gender里

        pElm->InsertEndChild( *pElmChild ); // 把Gender插入到主Element里

        SAFE_DELETE( pElmChild ); // 删除已经用完的Gender

        SAFE_DELETE( pText ); // 删除这个Text

     

        // 插入年龄(以子Element形式)

        pElmChild = new TiXmlElement( "age" ); // 建立一个子Element叫Age

        sprintf( sBuf, "%d", resume.nAge ); // 把Age变成字符串临时存进sBuf里

        pText = new TiXmlText( sBuf ); // 建立一个Age的子Element(一个Text形式的子元素)

        pElmChild->InsertEndChild( *pText ); // 把这个Age的子Element插入Age里

        pElm->InsertEndChild( *pElmChild ); // 把Age插入到主Element里

        SAFE_DELETE( pElmChild ); // 删除已经用完的Age

        SAFE_DELETE( pText ); // 删除这个Text

     

        // 插入技能子节点

        pElmChild = new TiXmlElement( "skills" ); // 建立一个子Element叫Skills

        sprintf( sBuf, "%d", resume.nNumSkill ); // 把Skill的数目变成字符串临时存进sBuf里

        pElmChild->SetAttribute( "num", sBuf ); // 把这个Skills的属性插入Skills里

        for( i=0; i<resume.nNumSkill; i++ )

        {

            exportSkill( pElmChild, resume.pSkill[i] ); // 插入一项技能

        }

        pElm->InsertEndChild( *pElmChild ); // 把Skills插入到主Element里

        SAFE_DELETE( pElmChild ); // 删除已经用完的Skills

        SAFE_DELETE( pText ); // 删除这个Text

     

        // 最后把整个Resume的子节点插入到父节点中

        pElmParent->InsertEndChild( *pElm );

     

        SAFE_DELETE( pElm ); // 删除子节点

    }

     

    void importResume( TiXmlElement* pElm, resume_t* pResume )

    {

        int i;

        char sBuf[NAME_LENGTH]; // 一个临时存放的字符串

        TiXmlElement* pElmChild = NULL; // 一个指向Element的指针

        TiXmlElement* pElmGrandChild = NULL; // 一个指向Element的指针

        TiXmlText* pText = NULL; // 一个指向Text的指针

        // 读入"resume"子节点

        strcpy( pResume->sName, pElm->Attribute( "name" ) );

     

        // 读入"gender"子节点

        pElmChild = pElm->FirstChildElement( "gender" );

        if( strcmp( "男", pElmChild->FirstChild()->Value() ) == 0 )

            pResume->isMan = true;

        else

            pResume->isMan = false;

     

        // 读入"age"子节点

        pElmChild = pElm->FirstChildElement( "age" );

        pResume->nAge = atoi( pElmChild->FirstChild()->Value() );

     

        // 读入"skills"子节点

        pElmChild = pElm->FirstChildElement( "skills" );

        pResume->nNumSkill = atoi( pElmChild->Attribute( "num" ) );

        pResume->pSkill = new skill_t[pResume->nNumSkill];

     

        pElmGrandChild = pElmChild->FirstChildElement( "skill" ); // 指向第一个Skill

        for( i=0; i<pResume->nNumSkill; i++ ) {

            importSkill( pElmGrandChild, &(pResume->pSkill[i]) ); // 读取一个Skill

            pElmGrandChild = pElmGrandChild->NextSiblingElement(); // 指向下一个Skill

        }

    }

     

    bool readXML( char* sFilePath, int* nNumResume, resume_t** ppResume )     {

        int i; // 用做循环的变量

        TiXmlElement* pElmChild = NULL; // 一个指向Element的指针

     

        TiXmlDocument xmlDoc( sFilePath ); // 输入XML路径

        if( !xmlDoc.LoadFile() ) // 读取XML并检查是否读入正确

            return false;

     

        TiXmlElement* pElmRoot = NULL; // 根节点

     

        pElmRoot = xmlDoc.FirstChildElement( "resumes" ); // 得到根节点

     

        if( !pElmRoot ) {

            return false;

        }

     

        *nNumResume = atoi( pElmRoot->Attribute( "num" ) ); // 读取Resume的数目

        *ppResume = new resume_t[*nNumResume]; // 分配Resume的空间

     

        pElmChild = pElmRoot->FirstChildElement( "resume" ); // 找出第一个Resume

        for( i=0; i<*nNumResume; i++ ) {

            importResume( pElmChild, &((*ppResume)[i]) ); // 读取Resume的内容

            pElmChild = pElmChild->NextSiblingElement(); // 找出下一个Resume

        }

     

        return true;

    }

     

    bool writeXML( char* sFilePath, int nNumResume, resume_t* pResume )
        {

        if( !sFilePath || !pResume )

            return false; // 确定指针存在

     

        int i; // 用做循环的变量

        char sBuf[NAME_LENGTH]; // 一个临时存放的字符串

     

        TiXmlElement* pElm = NULL; // 一个指向Element的指针

        TiXmlDeclaration Declaration( "1.0","gb2312", "yes" ); // 建立XML头结构

     

        TiXmlDocument xmlDoc( sFilePath ); // 用存档的文件名字来建立一个XML文件

        xmlDoc.InsertEndChild( Declaration ); // 把XML头结构插入当前文档

            // 插入根节点“Resumes”
            pElm = new TiXmlElement( "resumes" ); // 建立根节点“Resumes”
            sprintf( sBuf, "%d", nNumResume ); // 把nNumResume变成字符串临时存进sBuf里

        pElm->SetAttribute( "num", sBuf ); // 建立一个Resumes的子Element


            for( i=0; i<2; i++ )
            {
                exportResume( pElm, pResume[i] ); // 在根节点上插入以上定义的2个简历
            }
            xmlDoc.InsertEndChild( *pElm );

        xmlDoc.SaveFile();

     

        SAFE_DELETE( pElm ); // 删除Element

     

        return true;

    }

     

     

    void main()

    {

        int i, j;

        // + == 设置两份简历 ==========================================================

        int nNumResume = 2;

        resume_t* pResume = new resume_t[ nNumResume ];

     

        // 1. 初始化第一份简历

        strcpy( pResume[0].sName, "裕作" );

        pResume[0].isMan = true;

        pResume[0].nAge = 26;

        pResume[0].nNumSkill = 2;

        pResume[0].pSkill = new skill_t[2];

     

        { // 设置技能列表结构

            strcpy( pResume[0].pSkill[0].sName, "编程" );

            strcpy( pResume[0].pSkill[1].sName, "吹牛" );

            pResume[0].pSkill[0].nLevel = 99;

            pResume[0].pSkill[1].nLevel = 1;

        }

     

        // 2. 初始化第二份简历

        strcpy( pResume[1].sName, "裕作 The Great" );

        pResume[1].isMan = true;

        pResume[1].nAge = 0;

        pResume[1].nNumSkill = 1;

        pResume[1].pSkill = new skill_t[1];

     

        { // 设置技能列表结构

            strcpy( pResume[1].pSkill[0].sName, "编程" );

            pResume[1].pSkill[0].nLevel = 100;

        }

        // - == 设置两份简历 ==========================================================

     

        // 把简历以XML形式写入磁盘

        if( !writeXML( XML_FILE, nNumResume, pResume ) )

        {

            printf( "ERROR: can't write the file." );

            return;

        }

     

        // 删除Resume

        nNumResume = 0;

        SAFE_DELETE_ARRAY( pResume );

        // 重新读入XML文件里的Resume数据

        if( !readXML( XML_FILE, &nNumResume, &pResume ) )

        {

            printf( "ERROR: can't read the file." );

            return;

        }

     

        // 把所有简历输出到屏幕

        if( pResume ) // 确定有Resume

        {

            for( i=0; i<nNumResume; i++ ) {

                printf( "简历:====================== " );

                printf( " 名字:%s ", pResume[i].sName );

                if( pResume[i].isMan )

                    printf( " 性别:男 " );

                else

                    printf( " 性别:女 " );

                printf( " 年龄:%d ", pResume[i].nAge );

                printf( " 职业技能: " );

                for( j=0; j<pResume[i].nNumSkill; j++ ) {

                    printf( " 技能名称:%s ", pResume[i].pSkill[j].sName );

                    printf( " 技能等级:%d ", pResume[i].pSkill[j].nLevel );

                }

            }

        }

    }

  • 相关阅读:
    【面积并】 Atlantis
    【动态前k大 贪心】 Gone Fishing
    【复杂枚举】 library
    【双端队列bfs 网格图建图】拯救大兵瑞恩
    【奇偶传递关系 边带权】 奇偶游戏
    【权值并查集】 supermarket
    CF w4d3 A. Pythagorean Theorem II
    CF w4d2 C. Purification
    CF w4d2 B. Road Construction
    CF w4d2 A. Cakeminator
  • 原文地址:https://www.cnblogs.com/blogofwu/p/3905134.html
Copyright © 2011-2022 走看看