您的位置:首页 > 编程语言 > C语言/C++

TinyXML(C++ XML解析库)

2013-11-01 14:33 344 查看
写一个XML文件 TinyXML 是一个mini的C++ XML解析库,它是非验证的,它可以很容易的集成到其他的程序中.它解析一份XML doc,以此创建一个可以被读、写,保存的DOM.它主要的类层次架构,函数原形详细说明参看:http://www.grinninglizard.com/tinyxml/index.html

// 以下以简单的程序TinyXMLTest为例 TinyXML中最根本的就是Document,所以无论是需要写一个XML文件,还是要读,都必须从一个Document开始,就是(1)的动作,在此没有给构造函数一个参数是因为我们的目的是为了写出一个XML文件,文件的名字就是传给TiXmlDocument的参数。声明,文档,注释,文本,元素,不明类型都是TinyXmlNode的子类,都是一个Node,TinyXmlNode是一个很复杂的东西,它如上所示:

#include

#include "tinyxml.h"

using namespace std;

int main(int argc, char** argv)

{

// (1) create a XML document

TiXmlDocument *myDoc = new TiXmlDocument();

Document类型的节点建立好以后,就需要给该DOM树结构一个根,即下面的(2),(3),(5),由于TinyXml是非验证的,所以理论上他是可以有两个Document的,(在内部通过对类型的判断来避免这一情况的发生),由于根是一个元素,而元素本质上就是一个容器,他可以有子元素,文本等,由于属性可以有多个,所以在内部它有一个TinyXmlAttrbuiteSet的成员,用以储存之,而在TinyXmlAttrbuiteSet中所存的Attrbuites是通过带”哨兵”的链表来实现.在每次链接时,都是放置在最后一个位置

//(2) create the Root and connect it

TiXmlElement *RootElement = new TiXmlElement("人员组");

myDoc->LinkEndChild(RootElement);

//(3 )create a person and connect it

TiXmlElement *PersonElement = new TiXmlElement("人员");

RootElement ->LinkEndChild(PersonElement);

如(4)所示,如果一个元素有属性需要设置,通过调用SetAttribute()方法,可以实现目标,在设置时,会在Element的内部的链表上搜索,如果已经有相应的属性名,那么视之为改写,如果没有则添加.

//(4) set the attribute fo Person

PersonElement ->SetAttribute("ID", "1");

//(5) create Elementy name && age and connect them

TiXmlElement* NameElement = new TiXmlElement("姓名");

TiXmlElement* AgeElement = new TiXmlElement("年龄");

PersonElement ->LinkEndChild(NameElement);

PersonElement ->LinkEndChild(AgeElement);

如6所示,文本应该是XML中最好处理的tag类型了,它在DOM树结构中只能以“叶子”的形式存在.

//(6) set element Name && age and connect it

TiXmlText *NameContent = new TiXmlText("周星星");

TiXmlText *AgeContent = new TiXmlText("20");

NameElement ->LinkEndChild(NameContent);

AgeElement ->LinkEndChild(AgeContent);

最麻烦的应该就是(7)了,首先以”w”方式打开star.xml文件(如果不存在,则创建),在SaveFile的内部经过一些预处理后,就进入了一个从TinyXmlBase,继承而来的方法Print,在打印的过程中,按深度优先,前序方式进行。

(1) 打印出自己的名字和第一个’<’ eg:

(2) 判断是否有属性,有则依次打印,直到结束 eg:

(3) 根据是否有子元素确定是打印出”/>” 还是’>’

(4) 若有子元素,递归

(5) 打印完成,关闭文件

(6) SaveFile返回

// (7) save the file

myDoc ->SaveFile("star.xml");

读一个XML文件

前面简要的分析了一下,如何用TinyXML完成一个DOM树的输出,这儿将要给出一个如何读入XML文件,并提取其中数据的案例: 前一份文档写了,用TinyXML输出DOM,与读入XML文件为DOM的第一步骤就是实例化一个TinyXMLDocument的对象。

#include

#include"tinyxml.h"

using namespace std;

class TiXmlDocument;

int main(int argc, char** argv)

{

// (1)create a XML Doc object

TiXmlDocument* myDoc = new TiXmlDocument("sample.xml");

myDoc->LoadFile();



这看着最简单的LoadFile函数在进入内部的时候,那个繁杂,怎一个“难”字了得。在内部文件以”rb”的方式打开,以使对TinyXML 能对EOL归一化( reading in binary mode so that tinyxml can normalize the EOL) ,文件被成功打开后,将取得文件的大小,以下代码可以轻松完成:

fseek( file, 0, SEEK_END ); // LewGun

length = ftell( file );

fseek( file, 0, SEEK_SET );

在内部实例化一个std::string(针对使用STL而言,如果没有,则会使用TinyXmlString)。将文件中的所有数据读出,读到一个临时缓冲区buf中,然后 根据地XML的规范,在对XML文件进行解析前,需要让他们归一化,即:让“\r\n”,或者多个‘\r’字符转化为单个\n

if ( *p == 0xa )

{

// Newline character. No special rules for this. Append all the characters

// since the last string, and include the newline.

data.append( lastPos, (p-lastPos+1) ); // append, include the newline

++p; // move past the newline

lastPos = p; // and point to the new buffer (may be 0)

assert( p <= (buf+length) );

}



将这append到刚才的那个string中。归一化完成,然后就调用Parse函数进行解析,在解析的过程中由刚才的串string将这c_str()后,逐个字符的的处理,在处理的过程中,由于在生成XML文档,为了结构良好,会有相当多的空格,要将之去掉,根据提取的字符,来针对不同的类型比如表示是一个声明,其将会是一个注释,实例化不同的类,在实例化的过程中仍然是以当前的节点即myDoc为根,来生成DOM树,当对string比对完成,相应的DOM树也生成完成.



// (2)获取到对应元素上的文本值和属性值

取得根元素.的并输出的操作

TiXmlElement* rootElement = myDoc->RootElement();

cout <<>Value() <<>

这与前面的LinkEndChild在理论上是一个相对应的操作

TiXmlElement* FirstPerson = rootElement->FirstChildElement();

// get the first persons's node Name && Age and attribute ID

TiXmlElement *NameElement = FirstPerson->FirstChildElement();

TiXmlElement *AgeElement = NameElement->NextSiblingElement();

此句代码需要主意的是,由于元素的内部的attributeSet是通过双向链表来放置属性的,且它有一个哨兵节点,该节点一直被放置在最后,而FirstAttribute()会在内部调用

First(){ return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }

Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }

TiXmlAttribute *IDAttribute = FirstPerson->FirstAttribute();

在此AgeElement/NameElement的子女就是Text类型的对象,对之取值就是前文的”周星星”/20

cout << NameElement->Value() << endl;

cout << AgeElement ->Value() << endl;

cout << IDAttribute->Value() << endl;

}



下面再贴个示例

/*功能2:按某个字段从xml档中获取到对应的值*/
	TiXmlElement* pElement1 = rootElement->FirstChildElement();
	bool bFind = false;
	if(pElement1)
	{
		while(!bFind)
		{
			TiXmlElement* pElement2 = pElement1->FirstChildElement("field");
			if(!pElement2)
			{
				pElement1 = pElement1->FirstChildElement();
				if(!pElement1)
				{
					break;
				}
				continue;
			}

			for(;pElement2;)
			{
				//获得指定元素上的属性值
				TiXmlAttribute* pAttribute = pElement2->FirstAttribute();
				std::string strAttrName = pAttribute->Name();
				std::string strTarget = "name";

				while(pAttribute)
				{
					strAttrName = pAttribute->Name();
					if(!strAttrName.compare(strTarget))
					{
						strTarget = "epcid";
						std::string strTargetValue = pAttribute->Value();
						if(!strTargetValue.compare(strTarget))
						{
							cout << strTargetValue << "--------" << endl;
							bFind = true;
							break;
						}
					}
					pAttribute = pAttribute->Next();
				}
				if(bFind)
				{
					break;
				}
				pElement2 = pElement2->NextSiblingElement();
			}
		}
	}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: