Win系统C++ TinyXML使用心得总结

一、TinyXml的特点

        TinyXml是一个基于DOM模型的、非验证的轻量级C 解释器。它是一个开源的解析XML的解析库,能够用于C++,能够在Windows或Linux中编译。这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树。

1. SAX和DOM

        目前XML的解析主要有两大模型:SAX和DOM。
        其中SAX是基于事件的,其基本工作流程是分析XML文档,当发现了一个新的元素时,产生一个对应事件,并调用相应的用户处理函数。这种方式占用内存少,速度快,但用户程序相应得会比较复杂。
        而DOM(文档对象模型),则是在分析时,一次性的将整个XML文档进行分析,并在内存中形成对应的树结构,同时,向用户提供一系列的接口来访问和编辑该树结构。这种方式占用内存大,速度往往慢于SAX,但可以给用户提供一个面向对象的访问接口,对用户更为友好。

2. 验证和非验证

       对 于一个特定的XML文档而言,其正确性分为两个层次。首先是其格式应该符合XML的基本格式要求,比如第一行要有声明,标签的嵌套层次必须前后一致等等, 符合这些要求的文件,就是一个合格的XML文件,称作well-formatted。但除此之外,一个XML文档因其内容的不同还必须在语义上符合相应的 标准,这些标准由相应的DTD文件或者Schema文件来定义,符合了这些定义要求的XML文件,称作valid。
       因此,解析器也分为两种,一种是验证的,即会跟据XML文件中的声明,用相应的DTD文件对XML文件进行校验,检查它是否满足DTD文件的要求。另一种是忽略DTD文件,只要基本格式正确,就可以进行解析。
        就我所知,验证的解析器通常都是比较重量级的。TinyXml不支持验证,但是体积很小,用在解析格式较为简单的XML文件,比如配置文件时,特别的合适。

二、构建与使用


1. 获取

      TinyXml从这里可以找到最新版本的源代码,目前的版本是 2.6.2 (截至2011.11.01)。好久没有更新了。

      在网上还有一个类同的TinyXml-2版本,github开源代码,其有在线html版本可以参阅。

2.构建

        TinyXml 在构建时可以选择是否支持STL,选择的话,则可以使用std::string,所以通常应在Windows上,TinyXml的源码包里提供了VC6的 工程文件,直接用它就可以生成两个静该打开这个选项。态库(带STL和不带STL),非常容易。唯一需要注意的是,默认生成的库是单线程的,如果用在多线 程的项目中,需要改动一下配置,生成相应的多线程库。

3. 使用

        构建了相应的库之后,在 使用了它们的工程中,只要在连接时把他们连上就行了。需要注意的是,如果需要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;
}

读XML示例代码:

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();
	}
}

三、 TinyXml的编程模型


1.类之间的关系

         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转换成文档等。

2.  需要注意的问题

2.1  各类之间的转换

       由 于各个节点类都从TiXmlNode继承,在使用时常常需要将TiXmlNode*类型的指针转换为其派生类的指针,在进行这种转换时,应该首先使用由 TiXmlNode类提供的一系列转换函数,如ToElement(void),而不是c 的dynamic_cast

2.2 检查返回值

       由于TinyXml是一个非校验的解析器,因此当解析一个文件时,很可能文件并不包含我们预期的某个节点,在这种情况下,TinyXml将返回空指针。因此,必须要对返回值进行检查,否则将很容易出现内存访问的错误。


四、总结

        TinyXml 最大的特点就是它很小,可以很方便的静态连接到程序里。对于像配置文件、简单的数据文件这类文件的解析,它很适合。但是由于它是非验证的,因此需要在程序 里做许多检查工做,加重了程序编写的负担。因此对于复杂的XML文件,我觉得最好还是用验证的解析器来处理。


  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值