// 以下以简单的程序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(); } } }