TinyXML(C++ XML解析库)

写一个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");

这看着最简单的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)

myDoc->LoadFile();


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

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 <<>FirstChild() ->Value() <<>

cout <<>FirstChild() ->Value() <<>

cout <<>Value() <<>

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值