TinyXML学习记录及整理
整理自
http://www.cnblogs.com/phinecos/archive/2008/03/11/1100912.html
http://www.cppblog.com/age100/archive/2010/05/12/115203.html
http://panpan.blog.51cto.com/489034/104961
及百度文库。
TinyXML是一个开源的解析XML的解析库,能够用于C++,能够在Windows或Linux中编译。这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树。
DOM模型即文档对象模型,是将整个文档分成多个元素(如书、章、节、段等),并利用树型结构表示这些元素之间的顺序关系以及嵌套包含关系。
首先从网上下载TinyXML的库,文件夹的名字是TinyXpath,在工程里做如下配置:
在附加包含路径里添加:你的tinyxpath路径/tinyxpath/include
在附加库路径里添加:你的tinyxpath路径/tinyxpath/lib
在对象/库路径里添加:tinyxpathd.lib,如果使用release版本,则是tinyxpath.lib。
另外,由于我开发的项目是多线程的,所以设置了多线程的环境,因此使用TinyXML没有出现问题。本人将TinyXML写在一个单独的C++工程进行测试,发现如果不设置多线程的环境,会出现链接错误。我觉得原因可能是TinyXML使用了多线程环境,因此需要设置多线程的环境。在工程/设置下的C/C++选项卡中,选择Code Generation,在Use run-time library中选择Debug MultiThreaed DLL即可。
元素函数总结
ValueStr //返回元素名称
SetValue //设置元素名称
Parent //返回父节点对象
FirstChild //返回第一个子节点
LastChild //返回最后一个子节点
IterateChildren //返回下一个子节点
InsertEndChild //在最后一个子节点后插入子节点
InsertBeforeChild //在指定的子节点前插入子节点
InsertAfterChild //在指定的子节点后插入子节点
ReplaceChild //替换指定的子节点
RemoveChild //删除指定的子节点
Clear //删除所有的子节点
PreviousSibling //返回同级中前一个节点
NextSibling //返回同级中后一个节点
NextSiblingElement //返回同级中后一个元素
FirstChildElement //返回第一个子元素节点
Attribute //返回元素中的属性值
QueryValueAttribute //返回元素中的属性值
SetAttribute //设置元素中的属性值
FirstAttribute //返回元素中第一个属性对象
LastAttribute //返回元素中最后一个属性对象
RemoveAttribute //删除元素中指定的属性对象
如下是一个XML片段:
<Persons>
<Person ID="1">
<name>周星星</name>
<age>20</age>
</Person>
<Person ID="2">
<name>白晶晶</name>
<age>18</age>
</Person>
</Persons>
在TinyXML中,根据XML的各种元素来定义了一些类:
TiXmlBase:整个TinyXML模型的基类。
TiXmlAttribute:对应于XML中的元素的属性。比如<Person ID="1">
TiXmlNode:对应于DOM结构中的节点。
TiXmlComment:对应于XML中的注释。
TiXmlDeclaration:对应于XML中的申明部分, 即<?versiong="1.0" ?>。
TiXmlDocument:对应于XML的整个文档。 如new TiXmlDocument("xxx.xm");
TiXmlElement:对应于XML的元素。 比如<Person ID="1">
TiXmlText:对应于XML的文字部分。 比如<age>18</age>
TiXmlUnknown:对应于XML的未知部分。
TiXmlHandler:定义了针对XML的一些操作。
一、读取XML(假设我们的Xml文档中的内容与上面的Xml内容一样)
//创建一个XML的文档对象。
TiXmlDocument *myDocument = new TiXmlDocument("Resources.xm");
myDocument->LoadFile();
//获得根元素,即Persons。
TiXmlElement *RootElement = myDocument.RootElement();
//输出根元素名称,即输出Persons。
cout << RootElement->Value() << endl;
//获得第一个Person节点。
TiXmlElement *FirstPerson = RootElement->FirstChildElement();
//获得第一个Person的name节点和age节点和ID属性。
TiXmlElement *NameElement = FirstPerson->FirstChildElement();
TiXmlElement *AgeElement = NameElement->NextSiblingElement();
TiXmlAttribute *IDAttribute = FirstPerson->FirstAttribute();
//输出第一个Person的name内容,即周星星;age内容,即20;ID属性,即1。
cout << NameElement->FirstChild()->Value << endl;
cout << AgeElement->FirstChild()->Value << endl;
cout << IDAttribute->Value() << endl;
二、生成XML内容
//创建一个XML的文档对象。
TiXmlDocument *myDocument = new TiXmlDocument();
//创建一个根元素并连接。
TiXmlElement *RootElement = new TiXmlElement("Persons");
myDocument->LinkEndChild(RootElement);
//创建一个Person元素并连接。
TiXmlElement *PersonElement = new TiXmlElement("Person");
RootElement->LinkEndChild(PersonElement);
//设置Person元素的属性。
PersonElement->SetAttribute("ID", "1");
//创建name元素、age元素并连接。
TiXmlElement *NameElement = new TiXmlElement("name");
TiXmlElement *AgeElement = new TiXmlElement("age");
PersonElement->LinkEndChild(NameElement);
PersonElement->LinkEndChild(AgeElement);
//设置name元素和age元素的内容并连接。
TiXmlText *NameContent = new TiXmlText("周星星");
TiXmlText *AgeContent = new TiXmlText("20");
NameElement->LinkEndChild(NameContent);
AgeElement->LinkEndChild(AgeContent);
//保存到文件
myDocument->SaveFile("要保存的xml文件名");//保存到文件!!!!!!!!!!!
这样,便创建了一个如下的xml文件:
<Persons>
<Person ID="1">
<name>周星星</name>
<age>20</age>
</Person>
</Persons>
<Class name="计算机软件班">
<Students>
<student name="张三" studentNo="13031001" sex="男" age="22">
<phone>88208888</phone>
<address>西安市太白南路二号</address>
</student>
<student name="李四" studentNo="13031002" sex="男" age="20">
<phone>88206666</phone>
<address>西安市光华路</address>
</student>
</Students>
</Class>
程序代码XmlParseExample.cpp如下所示:
#include <iostream>
#include <string>
#include <tinyxml.h>
using std::string;
int main()
{
TiXmlDocument* myDocument = new TiXmlDocument();
myDocument->LoadFile("Students.xml");
TiXmlElement* rootElement = myDocument->RootElement(); //Class
TiXmlElement* studentsElement = rootElement->FirstChildElement(); //Students
TiXmlElement* studentElement = studentsElement->FirstChildElement(); //Students
while ( studentElement ) {
TiXmlAttribute* attributeOfStudent = studentElement->FirstAttribute(); //获得student的name属性
while ( attributeOfStudent ) {
std::cout << attributeOfStudent->Name() << " : " << attributeOfStudent->Value() << std::endl;
attributeOfStudent = attributeOfStudent->Next();
}
TiXmlElement* phoneElement = studentElement->FirstChildElement();//获得student的phone元素
std::cout << "phone" << " : " << phoneElement->GetText() << std::endl;
TiXmlElement* addressElement = phoneElement->NextSiblingElement();
std::cout << "address" << " : " << phoneElement->GetText() << std::endl;
studentElement = studentElement->NextSiblingElement();
}
return 0;
}
程序运行结果如下:
name : 张三
studentNo : 13031001
sex : 男
age : 22
phone : 88208888
address : 88208888
name : 李四
studentNo : 13031002
sex : 男
age : 20
phone : 88206666
address : 88206666
读者对象:对TinyXml有一定了解的人。本文是对TinyXml工具的一些知识点的理解。
需要讨论的请联系:QQ :471202412
1 TinyXml中对TiXmlNode进行了分类,是用一个枚举进行描述的。
enum NodeType
{
DOCUMENT, 文档节点
ELEMENT, 元素节点
COMMENT, 注释
UNKNOWN, 未知节点
TEXT, 文本节点
DECLARATION, 声明节点
TYPECOUNT 还没弄清楚
};
TiXmlNode * pNode->Type() 函数可以返回节点的类型。
枚举的比较方法:TiXmlText::TEXT == pNode->Type();
这几个类型非常重要,尤其是在遍历xml时或者查找一个节点时
我对节点和元素的理解如下:为了说明问题,我使用下面的xml文档来举例说明
<?xml version="1.0" encoding="gb2312"?>
<Persons>
<person Id="200" Shengao=34 ClassName="计本0508">
<name>vertor</name>
<age>20</age>
<address encode="utf-8">
<country>中国</country>
<province>山西</province>
<village>王大庄</village>
</address>
</person>
</Persons>
2.1 节点:一种对文档结构的描述对象
2.2 元素:对文档某一个数据块的描述
2.3 文本是指没有孩子的节点
例如<village>大王庄</village> 文本节点是:"大王庄"
然而判断一个节点是否是文本节点时并不是根据pNode->NoChildren()来判断,而是根据节点的类型来判断
因为如果一个节点形如:<village></village>它也是没有孩子节点的。
2.4 节点类可以转换成元素对象。
例如 TiXmlElement * pElement = pNode->ToElement();
那什么时候需要转换成元素呢?
当你需要元素的一些属性值是就需要转换了。
2.5 元素跟节点都有关于访问孩子的函数,
元素访问孩子的函数:
FirstChildElement() 返回当前元素的孩子元素
NextSiblingElement() 返回当前元素的同级元素
节点访问节点孩子的函数:
FirstChild() 返回当前节点的孩子节点
NextSibing() 返回当前节点的同级下一个节点
个人觉得 元素访问和节点访问在一般的访问下没有区别,两者都可以访问的孩子
对于一些特殊的情况下才需要区分。比如你要访问属性时,就需要用元素来找到第一个属性值。
2.6 对于遍历一个xml文档时,思路一般是这样的:
1 载入一个xml
2 获得根元素(不是根节点)
3 循环访问每一个根元素的子元素
4 对每一个子元素进行解析。
4.1 获取子元素的类型Type
4.2 switch(Type)
case TEXT:
输出文本节点的值pNode->value()
case ELEMENT:
获取元素的value(这里的value指的是元素的名字,例如:person元素)
循环获取元素的每一个属性
a 得到元素的第一个属性
b do——while循环获取每一个属性和值。
case COMMENT: 暂时不用管
case UNKNOWN: 暂时不用管
case DECLARATION:
获取元素的版本,编码方式等等
4.3 循环遍历子元素的下一级元素(即孙子元素) 在这里也可以遍历孙子节点。
递归调用第四步。
基本思路就是这样,具体代码见后面
2.7 如果定位一个节点
唯一确定一个节点的方法是根据节点名,属性名,属性值
1 根据xml的遍历思想找到与给定节点名一样的节点
2 如果这个节点有属性并且属性名和值与给定的一致,说明找到了。
3 如果没有一致的,说明解析失败。
4 如果没有给定属性名和值,则可以默认只查找与节点名一致的节点。
2.8 编码问题
用TinyXml加载一个xml文档时,根据文档的编码方式来加载,在操作过程中需要进行编码转换
如果encoding=utf-8 则在遍历时,需要进行编码转换,具体转换还没找到方法。
2.9 指针的 new和释放。
TinyXml已经帮我们把指针分配的内存进行了管理,在析构函数中进行了处理,我们不需要处理new出来的指针
如果我们显示的delete时,有可能影响程序运行。
3.0 对于添加一个节点,删除一个节点,更新一个节点时,都需要在最后SaveFile,我就好几次忘了SaveFile,所以调了老半天。
3.1 总的来说,Tinyxml还是不错的,以后继续学习。
部分功能代码
3.2 对于插入一个节点,首先获取要插入节点的父节点,然后进行插入,最需要注意的是在查询父节点的是时候,必须对应同一个文本对象来操作。有可能在两个函数中同时打开了同一个xml文档,虽然名字一样,但是不是同一个xmldocument对象,所以操作会失败。
最后要保存。
/************************************************************************/
/* 创建一个xml文档 */
/************************************************************************/
void createXml()
{
//创建一个XML的文档对象。
TiXmlDocument *myDocument = new TiXmlDocument();
TiXmlDeclaration* decl = new TiXmlDeclaration("1.0","gb2312","yes");
myDocument->LinkEndChild(decl);
//创建一个根元素并连接。
TiXmlElement *RootElement = new TiXmlElement("Persons");
myDocument->LinkEndChild(RootElement);
for(int i=0; i<10;i++)
{
//创建一个Person元素并连接。
TiXmlElement *PersonElement = new TiXmlElement("Person");
RootElement->LinkEndChild(PersonElement);
//设置Person元素的属性。
PersonElement->SetAttribute("ID", i);
//创建name元素、age元素并连接。
TiXmlElement *NameElement = new TiXmlElement("name");
TiXmlElement *AgeElement = new TiXmlElement("age");
PersonElement->LinkEndChild(NameElement);
PersonElement->LinkEndChild(AgeElement);
//设置name元素和age元素的内容并连接。
TiXmlText *NameContent = new TiXmlText("周星星");
TiXmlText *AgeContent = new TiXmlText("20");
NameElement->LinkEndChild(NameContent);
AgeElement->LinkEndChild(AgeContent);
}
//保存到文件
myDocument->SaveFile("test.xml");
}
/************************************************************************/
/* 遍历一个xml文档 */
/************************************************************************/
void readXml()
{
//创建一个XML的文档对象。
TiXmlDocument *myDocument = new TiXmlDocument("Person.xml");
myDocument->LoadFile();
//获得xml的头,即声明部分
TiXmlDeclaration* decl = myDocument->FirstChild()->ToDeclaration();
cout << "xml文件的版本是:" << decl->Version() << endl;
cout << "xml的编码格式是:" << decl->Encoding() << endl;
//获得根元素
TiXmlElement *RootElement = myDocument->RootElement();
//输出根元素名称
cout << RootElement->Value() << endl;
TiXmlNode* pNode = NULL;
string msg = "";
for(pNode=RootElement->FirstChildElement();pNode;pNode=pNode->NextSiblingElement())
{
msg += dumpNode(pNode,0);
}
cout << msg << endl;
}
************************************************************************/
/*描述:遍历一个元素
时间:2011-5-1
参数说明:pNode节点,flag 节点嵌套层数
/************************************************************************/
string dumpNode(TiXmlNode * pNode,int flag)
{
string msg = "";
if(pNode == NULL)
{
return "";
}
TiXmlText * pText = NULL;
TiXmlNode * pChildNode = NULL;
int t = pNode->Type();
if(t == TiXmlText::TEXT) //节点类型是text节点
{
pText = pNode->ToText();
string text = pText->Value();
if(!text.empty())
{
msg = msg + "="+ text;
}
}
else if(t == TiXmlText::ELEMENT) //节点类型是Element
{
msg = msg + "\r\n";
int num = flag;
while(num >= 1)
{
msg = msg + "\t";
num--;
}
msg = msg + pNode->Value();
//输出属性
TiXmlElement * pElement = pNode->ToElement();
TiXmlAttribute * pAttr = pElement->FirstAttribute();
TiXmlAttribute * pNextAttr =NULL;
string tmpAttrMsg = "[";
if(pAttr != NULL)
{
string tmpAttrVal = "";
string tmpAttrName = "";
do
{
tmpAttrVal = pAttr->Value();
tmpAttrName = pAttr->Name();
tmpAttrMsg += tmpAttrName+"=" + tmpAttrVal+","; //各个属性之间用逗号分隔
}while(pAttr = pAttr->Next());
tmpAttrMsg = tmpAttrMsg.erase(tmpAttrMsg.find_last_of(","));
}
tmpAttrMsg += "]";
msg += tmpAttrMsg;
}
//循环访问它的每一个元素
for(pChildNode=pNode->FirstChild();pChildNode!=0;pChildNode = pChildNode->NextSibling())
{
msg = msg + dumpNode(pChildNode,flag+1);
}
return msg;
}
/************************************************************************/
/* 查询出唯一节点 */
/* 参数说明:
string nodeName 节点名
string nodeAttrName 节点的属性
string nodeAttrValue 节点属性的值
/************************************************************************/
TiXmlNode * SelectSingleNode(string nodeName,string nodeAttrName,string nodeAttrValue)
{
//加载一个XML的文档对象。
TiXmlDocument *xmlDoc = new TiXmlDocument("Person.xml");
if(!xmlDoc->LoadFile()) //是tinyXml会自动处理文档的BOM
{
return NULL;
}
if(xmlDoc == NULL)
{
return NULL;
}
//获得根元素
TiXmlElement *RootElement = xmlDoc->RootElement();
if(RootElement == NULL)
{
cout << "解析错误,无法获取根元素" << endl;
return NULL;
}
TiXmlNode * pNode = NULL;
TiXmlNode * pSelectNode = NULL;
string msg = "";
for(pNode=RootElement->FirstChildElement();pNode;pNode=pNode->NextSiblingElement())
{
pSelectNode = selectChildNode(pNode,nodeName,nodeAttrName,nodeAttrValue);
if(pSelectNode)
{
break;
}
}
if(pSelectNode)
{
cout << "解析成功" << endl;
cout << pSelectNode->Value() << endl;
return pSelectNode;
}
else
{
cout << "解析错误,无法获取节点" << endl;
return NULL;
}
}
/************************************************************************/
/*
根据父节点循环遍历查找子节点
参数说明
noteName 节点名
noteAttrName 属性名
noteAttrValue 属性值
/************************************************************************/
TiXmlNode * selectChildNode(TiXmlNode * pNode,string nodeName,string nodeAttrName,string nodeAttrValue)
{
if(pNode == NULL)
{
return NULL;
}
TiXmlNode * pSelectedNode = NULL;
TiXmlNode * pChildNode = NULL;
int t = pNode->Type();
switch (t)
{
case TiXmlText::DOCUMENT:
case TiXmlText::DECLARATION:
case TiXmlText::TEXT:
case TiXmlText::UNKNOWN:
case TiXmlText::COMMENT:
break;
case TiXmlText::ELEMENT:
if(pNode->Value() == nodeName)
{
//cout << pNode->Value() << endl;
if(!nodeAttrName.empty() && !nodeAttrValue.empty())
{
TiXmlElement * pElement = pNode->ToElement();
TiXmlAttribute * pAttr = pElement->FirstAttribute();
TiXmlAttribute * pNextAttr =NULL;
if(pAttr != NULL)
{
do
{
if(pAttr->Name()==nodeAttrName&&pAttr->Value()== nodeAttrValue)
{
//cout << pAttr->Value() << endl;
return pNode;
}
}while(pAttr = pAttr->Next());
}
}
else
{
return pNode;
}
}
else
{
//循环访问它的每一个元素
for(pChildNode=pNode->FirstChild();
pChildNode!=0;
pChildNode = pChildNode->NextSibling())
{
pSelectedNode = selectChildNode(
pChildNode,
nodeName,
nodeAttrName,
nodeAttrValue);
if(pSelectedNode)
{
return pSelectedNode;
}
}
}
default:break;
}
return NULL;
}
/************************************************************************/
/* 普通插入一个节点,还不完善。 */
/************************************************************************/
bool insert()
{
//加载一个XML的文档对象。
TiXmlDocument *myDocument = new TiXmlDocument("Person.xml");
myDocument->LoadFile();
if(myDocument == NULL)
{
return false;
}
//获得xml的头,即声明部分
TiXmlDeclaration* decl = myDocument->FirstChild()->ToDeclaration();
if(decl != NULL)
{
cout << "xml文件的版本是:" << decl->Version() << endl;
cout << "xml的编码格式是:" << decl->Encoding() << endl;
}
//获得根元素
TiXmlElement *RootElement = myDocument->RootElement();
if(RootElement != NULL)
{
//创建一个Person元素并连接。
TiXmlElement *PersonElement = new TiXmlElement("Person");
PersonElement->SetAttribute("Id",1);
RootElement->LinkEndChild(PersonElement);
TiXmlText *textElement = new TiXmlText("Jam");
PersonElement->LinkEndChild(textElement);
//增加一个team元素
TiXmlElement *TeamElement = new TiXmlElement("team");
TeamElement->SetAttribute("TID","001");
RootElement->LinkEndChild(TeamElement);
//增加team的子节点name
TiXmlElement *teamName = new TiXmlElement("name");
TiXmlText *nameText = new TiXmlText("workgroup");
teamName->LinkEndChild(nameText);
TeamElement->LinkEndChild(teamName);
//增加team的子节点type
TiXmlElement *teamType = new TiXmlElement("type");
TiXmlText *typeText = new TiXmlText("SI");
teamType->LinkEndChild(typeText);
TeamElement->LinkEndChild(teamType);
myDocument->SaveFile("Person.xml");
//输出根元素名称
cout << RootElement->Value() << endl;
return true;
}
return false;
}
/************************************************************************/
/* 获取一个节点的属性 */
/************************************************************************/
string getAttribute(TiXmlNode * pNode)
{
if(pNode == NULL) return "";
//输出属性
string msg = "";
TiXmlElement * pElement = pNode->ToElement();
TiXmlAttribute * pAttr = pElement->FirstAttribute();
TiXmlAttribute * pNextAttr =NULL;
string tmpAttrMsg = "[";
if(pAttr != NULL)
{
string tmpAttrVal = "";
string tmpAttrName = "";
do
{
tmpAttrVal = pAttr->Value();
tmpAttrName = pAttr->Name();
tmpAttrMsg += tmpAttrName+"=" + tmpAttrVal+","; //各个属性之间用逗号分隔
}while(pAttr = pAttr->Next());
tmpAttrMsg = tmpAttrMsg.erase(tmpAttrMsg.find_last_of(","));
}
tmpAttrMsg += "]";
msg += tmpAttrMsg;
}
/************************************************************************/
/* 在指定位置插入一个元素 */
/************************************************************************/
bool insertAElement(TiXmlElement * pElement)
{
//加载一个XML的文档对象。
TiXmlDocument *xmlDoc = new TiXmlDocument("Person.xml");
xmlDoc->LoadFile();
if(xmlDoc == NULL) return false;
//获得xml的头,即声明部分
TiXmlDeclaration* decl = xmlDoc->FirstChild()->ToDeclaration();
if(decl != NULL)
{
cout << "xml文件的版本是:" << decl->Version() << endl;
cout << "xml的编码格式是:" << decl->Encoding() << endl;
}
//获得根元素
TiXmlElement *RootElement = xmlDoc->RootElement();
if(RootElement != NULL)
{
TiXmlNode * pNode = SelectSingleNode(xmlDoc,"name","length","100");
if(pNode == NULL)
{
return false;
}
//创建一个Person元素并连接。
TiXmlElement *pNewElement = new TiXmlElement("Person");
if(pNewElement == NULL)
{
return false;
}
pNewElement->SetAttribute("Id","1");
TiXmlText *textElement = new TiXmlText("gbnn");
if(textElement == NULL)
{
return false;
}
pNewElement->LinkEndChild(textElement);
TiXmlNode * pRet = pNode->InsertBeforeChild(pNode->LastChild(),*pNewElement);
//TiXmlNode * pRet = pNode->LinkEndChild(pNewElement);
xmlDoc->Print();
bool b = xmlDoc->SaveFile();
if(b)
{
cout << "添加成功" << endl;
return b;
}
else
{
cout << "添加失败" << endl;
return false;
}
}
else
{
return false;
}
}