本文共 5163 字,大约阅读时间需要 17 分钟。
写一个XML文件 TinyXML 是一个mini的C++ XML解析库,它是非验证的,它可以很容易的集成到其他的程序中.它解析一份XML doc,以此创建一个可以被读、写,保存的DOM.它主要的类层次架构,函数原形详细说明参看: // 以下以简单的程序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 IDTiXmlElement *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(); } } }
转载地址:http://ogoxi.baihongyu.com/