TinyXml是一个基于DOM模型的、非验证的轻量级C 解释器。它是一个开源的解析XML的解析库,能够用于C++,能够在Windows或Linux中编译。这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树。
目前XML的解析主要有两大模型:SAX和DOM。
其中SAX是基于事件的,其基本工作流程是分析XML文档,当发现了一个新的元素时,产生一个对应事件,并调用相应的用户处理函数。这种方式占用内存少,速度快,但用户程序相应得会比较复杂。
而DOM(文档对象模型),则是在分析时,一次性的将整个XML文档进行分析,并在内存中形成对应的树结构,同时,向用户提供一系列的接口来访问和编辑该树结构。这种方式占用内存大,速度往往慢于SAX,但可以给用户提供一个面向对象的访问接口,对用户更为友好。
对 于一个特定的XML文档而言,其正确性分为两个层次。首先是其格式应该符合XML的基本格式要求,比如第一行要有声明,标签的嵌套层次必须前后一致等等, 符合这些要求的文件,就是一个合格的XML文件,称作well-formatted。但除此之外,一个XML文档因其内容的不同还必须在语义上符合相应的 标准,这些标准由相应的DTD文件或者Schema文件来定义,符合了这些定义要求的XML文件,称作valid。
因此,解析器也分为两种,一种是验证的,即会跟据XML文件中的声明,用相应的DTD文件对XML文件进行校验,检查它是否满足DTD文件的要求。另一种是忽略DTD文件,只要基本格式正确,就可以进行解析。
就我所知,验证的解析器通常都是比较重量级的。TinyXml不支持验证,但是体积很小,用在解析格式较为简单的XML文件,比如配置文件时,特别的合适。
TinyXml从这里可以找到最新版本的源代码,目前的版本是 2.6.2 (截至2011.11.01)。好久没有更新了。
在网上还有一个类同的TinyXml-2版本,github开源代码,其有在线html版本可以参阅。
TinyXml 在构建时可以选择是否支持STL,选择的话,则可以使用std::string,所以通常应在Windows上,TinyXml的源码包里提供了VC6的 工程文件,直接用它就可以生成两个静该打开这个选项。态库(带STL和不带STL),非常容易。唯一需要注意的是,默认生成的库是单线程的,如果用在多线 程的项目中,需要改动一下配置,生成相应的多线程库。
构建了相应的库之后,在 使用了它们的工程中,只要在连接时把他们连上就行了。需要注意的是,如果需要STL支持,在编译用到了TinyXml的文件时,需要定义一个宏 TIXML_USE_STL,对gcc,可以使用参数-DTIXML_USE_STL,对cl.exe(VC),可以使用参数 /DTIXML_USE_STL,如果嫌麻烦,可以直接定义在 tinyxml.h文件里。
TinyXml它由两个头文件(.h文件)和四个CPP文件(.cpp文件)构成,用的时候,只要将(tinyxml.h、tinystr.h、tinystr.cpp、tinyxml.cpp、tinyxmlerror.cpp、tinyxmlparser.cpp)导入工程就可以用它的东西了。如果需要,可以将它做成自己的DLL来调用。
简单示例:
#include "tinyxml.h" #include "tinystr.h" #include <iostream> using namespace std; int main(int argc, char *argv[]) { if(argc != 2) { cout << "usage: "<<argv[0] << " xmlfile" << endl; return 1; } TiXmlDocument doc(argv[1]); bool loadOk = doc.LoadFile(); if (!loadOk) { cout << "could load:" << doc.ErrorDesc() << endl; } TiXmlPrinter printer;//提供的工具类,目的是将xml的数据按格式输出 doc.Accept(&printer); cout << printer.CStr() << endl;//输出 TiXmlElement*node = doc.FirstChildElement();//获取第一个element节点 cout << node->Value() << endl;//输出节点的值 string t; node->QueryValueAttribute("type", &t);//获取节点属性 cout << t << endl; doc.FirstChild()->NextSibling()->ToElement()->QueryStringAttribute("type", &t);//获取第二个子节点的数据 cout << "2:" << t << endl; //使用遍历的方式进行处理 TiXmlNode* child = NULL; TiXmlElement* element = NULL; TiXmlAttribute *attr = NULL; int ct; while(child = doc.FirstChild()->IterateChildren(child)) { cout << child->ValueStr() << "\t"; ct = child->Type(); cout << ct << "\t"; //根据不同的节点类型做相应处理 switch(ct) { case TiXmlNode::TINYXML_TEXT: break; case TiXmlNode::TINYXML_ELEMENT: element = child->ToElement(); attr = element->FirstAttribute(); while(attr) { cout << attr->NameTStr() << "=" << attr->ValueStr() << '\t'; attr = attr->Next(); } break; } } return 0; }写XML示例代码:
void CPrintObj::WriteXML(CString &path) { TiXmlDocument* xmlDoc = new TiXmlDocument(); TiXmlElement element("AutoDraw"); TiXmlNode* rootNode = xmlDoc->InsertEndChild(element); TiXmlNode* curNode = InsertNode(rootNode, "Paper"); WriteData(curNode, "Width", m_papp_data->ppaper_data->width); WriteData(curNode, "Height", m_papp_data->ppaper_data->height); WriteData(curNode, "FilterType", m_papp_data->m_nFileterType); WriteData(curNode, "A0A1Lengthen", m_papp_data->m_nSelA0A1Length); WriteData(curNode, "Code", m_papp_data->ppaper_data->code); WriteData(curNode, "AutoDrawType", m_papp_data->auto_draw_style); WriteData(curNode, "XCleanrance", m_papp_data->m_nXDrawingCleanrance); WriteData(curNode, "YCleanrance", m_papp_data->m_nYDrawingCleanrance); WriteText(curNode, "OutputPath", m_szUserSaveFilePath.GetBuffer()); WriteData(curNode, "IsSavePDF", m_papp_data->m_nPDF); list_head *auto_draw_iter = &m_papp_data->auto_draw_list; while((auto_draw_iter = auto_draw_iter->next) != &m_papp_data->auto_draw_list) { curNode = InsertNode(rootNode, "Page"); struct auto_draw_data *pauto_draw_data = list_entry(auto_draw_iter, struct auto_draw_data, list); WriteText(curNode, "FilePath", pauto_draw_data->filename); WriteData(curNode, "Width", pauto_draw_data->width); WriteData(curNode, "Height", pauto_draw_data->height); WriteData(curNode, "Code", pauto_draw_data->code); WriteData(curNode, "A0A1Lengthen", pauto_draw_data->m_nA0A1_Lenthen); } char* filePath = WcharToChar(path); xmlDoc->SaveFile(filePath); xmlDoc->Clear(); delete xmlDoc; delete filePath; }
void CDPrintObj::LoadData() { TCHAR szPath[MAX_PATH]; GetModuleFileName(NULL, szPath , MAX_PATH); CString strFilePath = szPath; strFilePath = strFilePath.Left(strFilePath.ReverseFind(_T('\\'))); CString strXmlFile; strXmlFile.Format(_T("%s\\dumpdata.xml"), strFilePath); TiXmlDocument *xmlDocument = new TiXmlDocument(); char strFile[MAX_PATH]; wstring2string(strXmlFile, strFile); xmlDocument->LoadFile(strFile); TiXmlHandle handle(xmlDocument); swprintf_s(m_papp_data->dump_filename, L"%S", handle.FirstChild("/APP_DATA/DUMP_FILENAME").ToElement()->GetText()); m_papp_data->new_paper_size.totalheight = atoi( handle.FirstChild("/APP_DATA/TOTALHEIGHT").ToElement()->GetText()); TiXmlElement *pRootElement = handle.FirstChild("/APP_DATA/DRW_DATA").ToElement(); TiXmlElement *pElement = pRootElement->FirstChildElement(); while(pElement) { drw_data *pdrw_data = new drw_data; swprintf_s(pdrw_data->filename, L"%S", pElement->FirstChildElement("FILENAME")->GetText()); list_add_tail(&pdrw_data->list, &m_papp_data->drw_list); TiXmlElement *pSubElement = pElement->FirstChildElement("SHEET_DATA"); while(pSubElement) { sheet_data *psheet_data = new struct sheet_data; list_add_tail(&psheet_data->list, &pdrw_data->sheet_list); swprintf_s(psheet_data->sheet_name, L"%S", pSubElement->FirstChildElement("SHEET_NAME")->GetText()); psheet_data->data.width = atoi(pSubElement->FirstChildElement("WIDTH")->GetText()); psheet_data->data.height = atoi(pSubElement->FirstChildElement("HEIGHT")->GetText()); psheet_data->data.xpos = atof(pSubElement->FirstChildElement("XPOS")->GetText()); psheet_data->data.ypos = atof(pSubElement->FirstChildElement("YPOS")->GetText()); psheet_data->data.code = atoi(pSubElement->FirstChildElement("CODE")->GetText()); psheet_data->data.flip = atoi(pSubElement->FirstChildElement("FLIP")->GetText()) > 0; pSubElement = pSubElement->NextSiblingElement(); } pElement = pElement->NextSiblingElement(); } }
C++ TinyXML是个解析库,主要由DOM模型类(TiXmlBase、TiXmlNode、TiXmlAttribute、TiXmlComment、TiXmlDeclaration、TiXmlElement、TiXmlText、TiXmlUnknown)和操作类(TiXmlHandler)构成。如图所示。
TiXmlBase:其它类的基类,是个抽象类
TiXmlNode:表示一个节点,包含节点的一般方法,如访问自节点、兄弟节点、编辑自身、编辑子节点
TiXmlDocument:表示整个XML文档,不对应其中某个特定的节点。
TiXmlElement:表示元素节点,可以包含子节点和TiXmlAttribute
TiXmlComment:表示注释
TiXmlDeclaration:表示声明
TiXmlText:表示文本节点
TiXmlUnknown:表示未知节点,通常是出错了
TiXmlAttribute:表示一个元素的属性
可以看到TinyXml中的注释comment,声明declaration,元素element,文本等都是节点Node的子类,也就是说可以把XMl文件中的各个元素当做节点来处理。Node类型也有到各个子类之间的转换方法,如ToElement()转换成元素,ToDocument转换成文档等。
由 于各个节点类都从TiXmlNode继承,在使用时常常需要将TiXmlNode*类型的指针转换为其派生类的指针,在进行这种转换时,应该首先使用由 TiXmlNode类提供的一系列转换函数,如ToElement(void),而不是c 的dynamic_cast
由于TinyXml是一个非校验的解析器,因此当解析一个文件时,很可能文件并不包含我们预期的某个节点,在这种情况下,TinyXml将返回空指针。因此,必须要对返回值进行检查,否则将很容易出现内存访问的错误。
TinyXml 最大的特点就是它很小,可以很方便的静态连接到程序里。对于像配置文件、简单的数据文件这类文件的解析,它很适合。但是由于它是非验证的,因此需要在程序 里做许多检查工做,加重了程序编写的负担。因此对于复杂的XML文件,我觉得最好还是用验证的解析器来处理。