實戰TinyXML
作者:裕作
(出處:http://blog.csdn.net/KyosukeNo1)
這幾天在埋頭寫自己的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
#i nclude "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")
#i nclude "string.h"
#i nclude "stdio.h"
#i nclude "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