C++使用tinyxml创建和解析xml文件(本文用于cocos2dx)

cocos2dx 2.2.5版里集成的tinyxml2不好用,总是报错,这里使用独立的第三方tinyxml库。

TinyXML是一个开源的解析XML的解析库,能够用于C++,能够在Windows,Linux中,mac上编译。这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树。

DOM模型即文档对象模型,是将整个文档分成多个元素(如书、章、节、段等),并利用树型结构表示这些元素之间的顺序关系以及嵌套包含关系。

(ps:还有一种SAX解析模式,自行google)


准备

去官网下载tinyxml包后解压,将

tinystr.cpp
tinystr.h
tinyxml.cpp
tinyxml.h
tinyxmlerror.cpp
tinyxmlparser.cpp

这6个文件添加到工程,建议复制到classes文件下。



测试

首先包含头文件

#include "tinyxml.h"

创建xml文件

void HelloWorld::createXML()
{
	//创建一个XML的文档对象。
	TiXmlDocument *myDocument = new TiXmlDocument();
	//创建xml文档声明并连接
	TiXmlDeclaration *declaration = new TiXmlDeclaration("1.0", "UTF-8", "");
	myDocument->LinkEndChild(declaration);
	//创建一个根元素并连接。
	TiXmlElement *RootElement = new TiXmlElement("Class");
	myDocument->LinkEndChild(RootElement);
	//创建一个Student元素并连接。
	TiXmlElement *student1 = new TiXmlElement("Student");
	RootElement->LinkEndChild(student1);
	//设置Student元素的属性。
	student1->SetAttribute("ID", "1");
	student1->SetAttribute("sex", "boy");
	student1->SetAttribute("hobby", "fight");
	//创建name元素、age元素并连接。
	TiXmlElement *NameElement1 = new TiXmlElement("name");
	TiXmlElement *AgeElement1 = new TiXmlElement("age");
	student1->LinkEndChild(NameElement1);
	student1->LinkEndChild(AgeElement1);
	//设置name元素和age元素的内容并连接。
	TiXmlText *NameContent1 = new TiXmlText("Ling Huchong");
	TiXmlText *AgeContent1 = new TiXmlText("22");
	NameElement1->LinkEndChild(NameContent1);
	AgeElement1->LinkEndChild(AgeContent1);


	//创建另一个Student元素并连接。
	TiXmlElement *student2 = new TiXmlElement("Student");
	RootElement->LinkEndChild(student2);
	//设置Student元素的属性。
	student2->SetAttribute("ID", "2");
	student2->SetAttribute("sex", "girl");
	student2->SetAttribute("hobby", "dance");
	//创建name元素、age元素并连接。
	TiXmlElement *NameElement2 = new TiXmlElement("name");
	TiXmlElement *AgeElement2 = new TiXmlElement("age");
	student2->LinkEndChild(NameElement2);
	student2->LinkEndChild(AgeElement2);
	//设置name元素和age元素的内容并连接。
	TiXmlText *NameContent2 = new TiXmlText("Ren Yingying");
	TiXmlText *AgeContent2 = new TiXmlText("18");
	NameElement2->LinkEndChild(NameContent2);
	AgeElement2->LinkEndChild(AgeContent2);
	//设置文件名,这是在cocos2dx里的路径写法,在标准c++中可以用string类型的绝对或相对路径字符串
	std::string Path = CCFileUtils::sharedFileUtils()->getWritablePath() + "test.xml";
	myDocument->SaveFile(Path.c_str());//保存到文件
	//删除文档对象
	delete myDocument;
}
其实,xml内容的增、删、改都跟写文档类似,无非是在内存中对节点树的操作,最后保存到文档。其中改节点,需要先clear标签文本值,再重新LinkEndChild,删除用remove或者clear

以上代码创建的xml文件如下

<?xml version="1.0" encoding="UTF-8" ?>
<Class>
    <Student ID="1" sex="boy" hobby="fight">
        <name>Ling Huchong</name>
        <age>22</age>
    </Student>
    <Student ID="2" sex="girl" hobby="dance">
        <name>Ren Yingying</name>
        <age>18</age>
    </Student>
</Class>
解析xml文件

void HelloWorld::parseXML()
{
	std::string Path = CCFileUtils::sharedFileUtils()->getWritablePath() + "test.xml";
	//创建一个XML的文档对象。
	TiXmlDocument *myDocument = new TiXmlDocument(Path.c_str());
	myDocument->LoadFile();
	//或者这样写
	/*TiXmlDocument *myDocument = new TiXmlDocument();
	myDocument->LoadFile(Path.c_str());*/
	TiXmlElement* rootElement = myDocument->RootElement();  //Class
	TiXmlElement* studentElement = rootElement->FirstChildElement();  //Students
	//遍历第一层结点
	while (studentElement) 
	{
		TiXmlAttribute* attributeOfStudent = studentElement->FirstAttribute();  //获得student的第一个属性
		//遍历student的属性
		while (attributeOfStudent) 
		{
			CCLog("%s:%s", attributeOfStudent->Name(), attributeOfStudent->Value());  //打印键值对
			attributeOfStudent = attributeOfStudent->Next();
		}
		TiXmlElement* Element = studentElement->FirstChildElement();//获得student的第一个元素
		//遍历student的元素
		while (Element)
		{
			CCLog("%s:%s", Element->Value(), Element->GetText());   //打印键值对
			Element = Element->NextSiblingElement();
		}
		studentElement = studentElement->NextSiblingElement();
	}
	//删除文档对象
	delete myDocument;
}

需要查找元素,就直接拿解析出来的value或者text值进行匹配比对,另外document有一个Print的函数,直接打印到控制台或者文件流


 

说明

关于TinyXML基本使用:

XML文档的结构:

TinyXml实现的时DOM访问模型,主要类间的关系如下图所示:

TiXmlBase:其他类的基类,是个抽象类

TiXmlNode:表示一个节点,包含一般方法,如访问自节点、兄弟节点、编辑自身、编辑子节点

TiXmlDocument:表示整个XML文档,不对应其中某个特定的节点。

TiXmlElement:表示元素节点,可以包含子节点和TiXmlAttribute

TiXmlComment:表示注释

TiXmlDeclaration:表示声明

TiXmlText:表示文本节点

TiXmlUnknown:表示未知节点,通常是出错了

TiXmlAttribute:表示一个元素的属性

 

详细使用:http://andylin02.iteye.com/blog/582334


注意:
  • 在cocos2dx中的中文解析出来cclog打印就乱码,需要iconv库的支持。
  • 标准c++工程解析打印到控制台也中文乱码,输出到文件就没问题。
  • 貌似tinyxml只能解析utf8编码的xml文档

后记:

tinyXml好像并没有给出一个直接遍历的函数,但是它能够从一个节点直接通向它的第一个子节点,最后一个子节点,上一个兄弟节点,下一个兄弟节点以及父节点。当然,也可以具体到第一个名为xxx的子节点或兄弟节点。
所以,想要完全遍历xml文件的树形结构,还需要你自己来处理。如果不在意效率的话,递归是逻辑关系最清楚的办法了。
关于递归解析xml节点

void ParseXmlText(TiXmlElement* pCurrentElement)   
{   
	if(NULL==pCurrentElement)   
		return; 
	TiXmlElement* pEle = NULL;   
	for (pEle = pCurrentElement->FirstChildElement(); pEle; pEle = pEle->NextSiblingElement())   
	{   
		cout<<pEle->Value()<<endl; //打印标签名
		//递归处理   
		ParseXmlText(pEle);   
		const char* pszText = pEle->GetText(); //尝试获得标签中间的文本
		if (NULL != pszText)    //如果不为空,说明是最后一层,标签中间有文本
			cout<<pszText<<endl;   //打印文本
	}   
}   

 

另外,还有一个api可能会用到,就是判断是否有子节点pCurrentNode->NoChildren(),返回false表示没有子节点了,当前节点是最后的两个标签之间的文本



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值