这几天在埋头写自己的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( "简历:======================\n" );

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

if( pResume[i].isMan )

printf( "\t性别:男\n" );

else

printf( "\t性别:女\n" );

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

printf( "\t职业技能:\n" );

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

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

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

}

}

}

}

tiny xml 使用总结的更多相关文章

  1. tiny中文乱码问题,不过仅适用于windows,所以xml不可以出现中文

    我是在SetAttribute() 函数之前使用的 SetAttribute(const char* name,const char * _value) 首先得到了一个CString 类型的变量 st ...

  2. XML解析器(转)

    常见C/C++ XML解析器有tinyxml.XERCES.squashxml.xmlite.pugxml.libxml等等,这些解析器有些是支持多语言的,有些只是单纯C/C++的.如果你是第一次接触 ...

  3. .NET平台开源项目速览-最快的对象映射组件Tiny Mapper之项目实践

    心情小札:近期换了工作,苦逼于22:00后下班,房间一篇狼藉~ 小翠鄙视到:"你就适合生活在垃圾堆中!!!" 晚上浏览博客园 看到一篇非常实用的博客:.NET平台开源项目速览(14 ...

  4. 推荐使用Tiny Framework web开发UI组件

    TINY FRAMEWORK 基于组件化的J2EE开发框架,from:http://www.tinygroup.org/   名字 Tiny名称的来历 取名Tiny是取其微不足道,微小之意. Tiny ...

  5. Play XML Entities

    链接:https://pentesterlab.com/exercises/play_xxe/course Introduction This course details the exploitat ...

  6. 比較全的XML系列工具 能够轻松实现排版、转换和打印!

    XML系列 --------------------------------------------------------------------------------1.Xsl Formatte ...

  7. ABAP下载xml文件

    [转http://www.cnblogs.com/byfhd/archive/2007/08/17/859829.html] ************************************* ...

  8. 基于深度学习的安卓恶意应用检测----------android manfest.xml + run time opcode, use 深度置信网络(DBN)

    基于深度学习的安卓恶意应用检测 from:http://www.xml-data.org/JSJYY/2017-6-1650.htm 苏志达, 祝跃飞, 刘龙     摘要: 针对传统安卓恶意程序检测 ...

  9. C++读取XML,tinyXml的使用

    前言: 最近在开发的过程中,有个需求是对xml进行格式转化,从一种格式转化到另外一种格式.因此,就需要读取xml进行处理.原本打算写成工具在linux下运行,不过后来考虑到和系统结合,最后也就使用了前 ...

随机推荐

  1. Html5所见即所得的几款框架

    http://www.csdn.net/article/2013-10-21/2817243-8-useful-html5-frameworks

  2. TF.Learn

    TF.Learn 手写文字识别   转载请注明作者:梦里风林Google Machine Learning Recipes 7官方中文博客 - 视频地址Github工程地址 https://githu ...

  3. Swift 可选类型-备

    我们先看看如下代码: var n1: Int = 10 n1 = nil         //编译错误 let str: String = nil    //编译错误 Int和String类型不能接受 ...

  4. SQL Fetch size

    JDBC performance tuning with optimal fetch size February 1, 2009 31 Comments Tuning performance usin ...

  5. Configuring HTTP and HTTPS

    Configuring HTTP and HTTPS .NET Framework (current version)   Other Versions   WCF services and clie ...

  6. js深入研究之神奇的匿名函数类生成方式

    <script type="text/javascript"> var Book = (function() { // 私有静态属性 ; // 私有静态方法 funct ...

  7. STL中,back_insert_iterator与back_inserter的区别。

    1.参考http://www.cplusplus.com网站关于back_insert_iterator与back_inserter的介绍之后,我总算明白了:back_insert_iterator, ...

  8. vim编辑器的设置文件

    vim配置特点: 1.按F5可以直接编译并执行C.C++.java代码以及执行shell脚本,按“F8”可进行C.C++代码的调试 2.自动插入文件头 ,新建C.C++源文件时自动插入表头:包括文件名 ...

  9. Java之Map

    Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象. Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象. code ...

  10. 运行tomcat7w.exe tomcat7.exe ,提示 指定的服务未安装 unable to open the service 'tomcat7'

    运行tomcat7w.exe tomcat7.exe ,提示 指定的服务未安装 unable to open the service 'tomcat7'(用的是绿色的Tomcat7) 解决方法: 打开 ...