操作xml文件——解析xml文件


其一:TinyXML 用法:读/写配置文件


1. TinyXML 的主页:
http://www.grinninglizard.com/tinyxml/

下载路径:
http://sourceforge.net/projects/tinyxml/

// 我下载时的最新版本为:tinyxml_2_6_2.zip


2. 使用方法
解压缩后,将这六个文件添加到c++工程中,分别是: tinystr.h、tinystr.cpp、tinyxml.h、tinyxml.cpp、tinyxmlerror.cpp、tinyxmlparser.cpp。
如果定义宏 TIXML_USE_STL,则 tinystr.h 和 tinystr.cpp 这两个文件可以不需要,我定义了这个宏。


3. 为了支持中文,需要生成 UTF-8 格式的文件,所以还需要将下载的 TinyXML 源代码修改一下,以写入 Windows 下 UTF-8 文件的 BOM 头:0xEF,0xBB,0xBF
在 tinyxml.h/tinyxml.cpp 中增加函数

tinyxml.h

[cpp] view plain @L_502_3@
  1. voidSetMicrosoftBOM(boolbBOM);


tinyxml.cpp

copy
    voidTiXmlDocument::SetMicrosoftBOM(boolbBOM)
  1. {
  2. useMicrosoftBOM=bBOM;
  3. }


// 在外部调用 TiXmlDocument 的 SaveFile() 函数之前,调用 SetMicrosoftBOM( true ),即可在生成的 xml 文件头写入 BOM 头。


4. 下面举例说明,读写的配置文件内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<Config>
<Database ip="192.168.1.33" port="3306" user="root" passwd="111111" dbname="mediadb" />
<Channels>
<Channel count="5">天龙八部</Channel>
<Channel count="5">笑傲江湖</Channel>
</Channels>
</Config>

5. 源码如下,(开始先得到 XML 文件的存取路径):

copy
    BOOLCgenwebDlg::OnInitDialog()
  1. ...
  2. ///////////////////////////////////////
  3. //生成配置文件名,带全路径
  4. CStringstrCurPath=_T("");
  5. GetModuleFileName(NULL,strCurPath.GetBuffer(MAX_PATH),MAX_PATH);
  6. strCurPath.ReleaseBuffer();
  7. CStringstrPath=strCurPath.Left(strCurPath.ReverseFind(_T('\\'))+1);
  8. CStringstrFile=strCurPath.Right(strCurPath.GetLength()-strCurPath.ReverseFind(_T('\\'))-1);
  9. strFile=strFile.Left(strFile.ReverseFind(_T('.')));
  10. m_strProfile=strPath+strFile+_T(".xml");
  11. }

// 读取 XML 配置文件

copy
    voidCgenwebDlg::ReadConfigFile()
  1. TiXmlDocument*content=newTiXmlDocument();
  2. content->LoadFile(m_strProfile.GetBuffer());
  3. m_strProfile.ReleaseBuffer();
  4. TiXmlHandledocHandle(content);
  5. TiXmlAttribute*pAttr=0;
  6. TiXmlElement*pDatabase=docHandle.FirstChild("Config").FirstChild("Database").ToElement();
  7. if(pDatabase)
  8. {
  9. m_etDB.SetWindowTextA(pDatabase->Attribute("ip"));
  10. m_etDBPort.SetWindowTextA(pDatabase->Attribute("port"));
  11. m_etUsername.SetWindowTextA(pDatabase->Attribute("user"));
  12. m_etPasswd.SetWindowTextA(pDatabase->Attribute("passwd"));
  13. m_etDBName.SetWindowTextA(pDatabase->Attribute("dbname"));
  14. }
  15. intnIndex=0;
  16. intnItem=0;
  17. char*text,mbs[256]={0};
  18. TiXmlElement*pChannel=docHandle.FirstChild("Config").FirstChild("Channels").FirstChild("Channel").ToElement();
  19. while(pChannel)
  20. nIndex=m_listChannels.GetItemCount();
  21. nItem=m_listChannels.InsertItem(nIndex,"");
  22. text=(char*)pChannel->GetText();
  23. if(UTF8ToMBS(mbs,256,text)>0)
  24. m_listChannels.SetItemText(nItem,mbs);
  25. text=(char*)pChannel->Attribute("count");
  26. pChannel=pChannel->NextSiblingElement();
  27. deletecontent;
  28. }
copy
    //写入XML配置文件
copy
    voidCgenwebDlg::WriteConfigFile()
  1. TiXmlDocument*pDoc=newTiXmlDocument;
  2. assert(pDoc);
  3. TiXmlDeclaration*pDeclaration=newTiXmlDeclaration(_T("1.0"),_T("UTF-8"),_T(""));
  4. assert(pDeclaration);
  5. pDoc->LinkEndChild(pDeclaration);
  6. TiXmlElement*pRootEle=newTiXmlElement(_T("Config"));
  7. assert(pRootEle);
  8. pDoc->LinkEndChild(pRootEle);
  9. TiXmlElement*pDatabase=newTiXmlElement(_T("Database"));
  10. assert(pDatabase);
  11. pRootEle->LinkEndChild(pDatabase);
  12. charconfig[256]={0};
  13. m_etDB.GetWindowTextA(config,sizeof(config)-1);
  14. pDatabase->SetAttribute(_T("ip"),config);
  15. m_etDBPort.GetWindowTextA(config,153); background-color:inherit; font-weight:bold">sizeof(config)-1);
  16. pDatabase->SetAttribute(_T("port"),config);
  17. m_etUsername.GetWindowTextA(config,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> pDatabase->SetAttribute(_T("user"),108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> m_etPasswd.GetWindowTextA(config,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> pDatabase->SetAttribute(_T("passwd"),248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> m_etDBName.GetWindowTextA(config,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> pDatabase->SetAttribute(_T("dbname"),108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> TiXmlElement*pChannels=newTiXmlElement(_T("Channels"));
  18. assert(pChannels);
  19. pRootEle->LinkEndChild(pChannels);
  20. charutf8[256]={0};
  21. intcount=m_listChannels.GetItemCount();
  22. for(inti=0;i<count;i++)
  23. TiXmlElement*pChannel=newTiXmlElement(_T("Channel"));
  24. assert(pChannel);
  25. pChannels->LinkEndChild(pChannel);
  26. m_listChannels.GetItemText(i,config,153); background-color:inherit; font-weight:bold">if(MBSToUTF8(utf8,sizeof(utf8),config)>0)
  27. TiXmlText*pName=newTiXmlText(utf8);
  28. pChannel->LinkEndChild(pName);
  29. }
  30. m_listChannels.GetItemText(i,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> pChannel->SetAttribute(_T("count"),248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> pDoc->SetMicrosoftBOM(true);
  31. pDoc->SaveFile(m_strProfile);
  32. deletepDoc;
  33. return;

  34. 6. 以上函数用到的 UTF8 和 MultiBytes 字符串互转函数如下:

    copy @H_502_693@
      //MBSToUTF8:stringconvertfunctions,convertMBSstringtoUTF8string.
    1. //@paramutf8:utf8stringconvertedto.
    2. //@paramsize:thesizeofutf8bufferpassed.
    3. //@parammbs:mbsstringthatneedtobeconverted.
    4. //@return:thelengthofresultstring.
    5. intMBSToUTF8(char*utf8,intsize,153); background-color:inherit; font-weight:bold">constchar*mbs)
    6. if(!utf8||!mbs)
    7. returnNULL;
    8. UINTnACP=GetACP();
    9. intdwNum=MultiByteToWideChar(nACP,mbs,-1,NULL,0);//CP_ACP
    10. if(dwNum<=0)
    11. wchar_t*pwText=NULL;
    12. pwText=newwchar_t[dwNum+1];
    13. if(!pwText)
    14. delete[]pwText;
    15. returnNULL;
    16. memset(pwText,dwNum*2+2);
    17. if(MultiByteToWideChar(nACP,pwText,dwNum)==0)intdwCount=WideCharToMultiByte(CP_UTF8,NULL);
    18. if(dwCount<=0)
    19. delete[]pwText;
    20. if(size<dwCount+1)
    21. memset(utf8,dwCount+1);
    22. if(WideCharToMultiByte(CP_UTF8,utf8,dwCount,NULL)==0)
    23. returndwCount;

    24. copy
        //UTF8ToMBS:stringconvertfunctions,convertUTF8stringtoMBSstring.
      1. //@parammbs:mbsstringconvertedto.
      2. //@paramsize:thesizeofmbsbufferpassed.
      3. //@paramutf8:utf8stringthatneedtobeconverted.
      4. intUTF8ToMBS(char*mbs,87); background-color:inherit; font-weight:bold">char*utf8)
      5. intdwNum=MultiByteToWideChar(CP_UTF8,0);
      6. if(MultiByteToWideChar(CP_UTF8,dwNum)==0)
      7. intdwCount=WideCharToMultiByte(nACP,NULL); memset(mbs,153); background-color:inherit; font-weight:bold">if(WideCharToMultiByte(nACP,NULL)==0)//CP_ACP
      8. 如下是一个XML片段:
        <Persons>
        PersonID="1name周星星</age20Person2白晶晶18
        在TinyXML中,根据XML的各种元素来定义了一些类:
        TiXmlBase:整个TinyXML模型的基类。
        TiXmlAttribute:对应于XML中的元素的属性
        TiXmlNode:对应于DOM结构中的节点。
        TiXmlComment:对应于XML中的注释。
        TiXmlDeclaration:对应于XML中的申明部分,即
        ?versiong1.0?>
        TiXmlDocument:对应于XML的整个文档。
        TiXmlElement:对应于XML的元素。
        TiXmlText:对应于XML的文字部分。
        TiXmlUnknown:对应于XML的未知部分。
        TiXmlHandler:定义了针对XML的一些操作。
        那我们如何使用这些类以及他们的方法来操纵我们的XML呢?请看下面。
        一、读取XML(假设我们的Xml文档中的内容与上面的Xml内容一样)
        //创建一个XML的文档对象。
        TiXmlDocument*myDocumentnewTiXmlDocument(填上你的Xml文件);
        myDocument
        ->LoadFile();
        获得根元素,即Persons。TiXmlElementRootElementmyDocument.RootElement();
        输出根元素名称,即输出Persons。cout<<Value()endl;
        获得第一个Person节点。FirstPersonFirstChildElement();
        获得第一个Person的name节点和age节点和ID属性NameElementFirstChildElement();
        TiXmlElement
        AgeElementNextSiblingElement();
        TiXmlAttribute
        IDAttributeFirstAttribute();
        输出第一个Person的name内容,即周星星;age内容,即20;ID属性,即1。FirstChild()Valueendl;
        cout
        endl;

        看,读取XML是不是很简单阿,和Java的XML解析库非常的相似,就是名字改了一下而已。
        二、生成XML内容
        TiXmlDocument();
        创建一个根元素并连接。TiXmlElement(LinkEndChild(RootElement);
        创建一个Person元素并连接。PersonElement);
        RootElement
        LinkEndChild(PersonElement);
        设置Person元素的属性SetAttribute(ID,);
        创建name元素、age元素并连接。);
        TiXmlElement
        );
        PersonElement
        LinkEndChild(NameElement);
        PersonElement
        LinkEndChild(AgeElement);
        设置name元素和age元素的内容并连接。TiXmlTextNameContentTiXmlText();
        TiXmlText
        AgeContent);
        NameElement
        LinkEndChild(NameContent);
        AgeElement
        LinkEndChild(AgeContent);
        保存到文件SaveFile(要保存的xml文件);
        这样,便创建了一个如下的xml文件
        >


        TinyXML入门教程

        TinyXML入门教程
        什么是XML?

        文档类

        创建文档对象
        3
        输出文档对象

        保存文档对象
        4
        返回第一个根元素
        5
        声明类

        注释类
        6
        元素类

        节点名

        父节点

        子节点
        7
        编辑子节点

        同级节点

        遍历元素
        8
        元素属性

        元素函数总结
        9
        属性
        10



        什么是XML?
        XML全称EXtensibleMarkupLanguage,翻译为可扩展标记语言,简而言之就是你可以自定义数据的标识,以此来区分各种不同的数据,以便于进行数据交换,例如html就可以理解为一种简单的xml语言。XML文件通常就是一个文本文件,可以使用任何编码



        上图就是我系统中一个xml文件的图标,使用VC2005打开它,你可以看到如下内容



        XML也是有这几个对象组成了,一般来说我们经常使用的类如下:
        lTiXmlDocument:文档类,它代表了整个xml文件
        lTiXmlDeclaration:声明类,它表示文件的声明部分,如上图所示。
        lTiXmlComment:注释类,它表示文件的注释部分,如上图所示。
        lTiXmlElement:元素类,它是文件的主要部分,并且支持嵌套结构,一般使用这种结构来分类的存储信息,它可以包含属性类和文本类,如上图所示。
        nTiXmlAttribute
        /TiXmlAttributeSet:元素属性,它一般嵌套在元素中,用于记录此元素的一些属性,如上图所示。
        nTiXmlText:文本对象,它嵌套在某个元素内部,如上图所示。

        TinyXml使用文档对象模型(DOM)来解析xml文件,这种模型的处理方式为在分析时,一次性的将整个XML文档进行分析,并在内存中形成对应的树结构,同时,向用户提供一系列的接口来访问和编辑该树结构。这种方式占用内存大,但可以给用户提供一个面向对象的访问接口,对用户更为友好,非常方便用户使用。下面我们依次来介绍各个类的用法

        文档类


        文档类代表一个XML文档,通过它,你可以保存,载入和打印输出文档。你可以通过以下方式载入xml文档到TiXmlDocument。

        创建文档对象
        l创建一个空的文档对象,然后载入一个xml文档
        使用到的函数原形如下:
        +boolLoadFile(conststd::string&filename)
        在程序中你可以如下使用:

        载入xml文档TiXmlDocumentdoc();
        doc.LoadFile(
        tutorial.xml);

        l
        、在构造函数中传入文档的名称,然后调用load函数完成解析载入
        使用到的函数原形如下:
        documentName);
        LoadFile();
        在程序中你可以如下使用:

        TiXmlDocumentdoc();
        doc.LoadFile();

        输出文档对象
        文档类提供了Print()函数用于在控制台输出当前的文档内容,这个函数的原形如下:
        voidPrint()
        在程序中你可以如下使用:

        );
        doc.LoadFile();
        doc.Print();
        输出文档tutorial.xml的内容如下:

        <?xmlversionstandaloneyesencodingutf-8

        <!--comment注释-->elementattributethisaattribute(这是一个属性)intfloat3.14subelement1
        Thisatext(这是一个文本)
        subelement2/>subelement3subelement4element
        在控制台中你可以得到如下输出

        由于文件使用UTF
        -8编码,而Windows下的控制台默认使用gb2312编码,因此会生成乱码。



        保存文档对象
        当然你也可以使用SaveFile()函数来进行另存为,这个函数的原形如下:
        filename)endl;
        doc.SaveFile(
        tutorial.txt);
        使用记事本打开tutorial.txt,你可以看到如下内容


        返回第一个根元素
        另外文档对象还提供了一个实用的函数用于返回第一个根对象,它可以让你方便的遍历整个文档结构,查找自己需要的数据。函数原形如下:
        RootElement()
        我们在介绍元素类的时候再详细介绍它的使用。

        声明类
        在标准的XML文件中,声明为文件的第一项,例如
        属性值,版本,编码和独立文件声明
        一般来说文档的第一行就是声明对象,你可以把文档对象的第一个子节点转换为声明对象。

        使用TinyXml的声明对象TiXmlDeclarationdecl;
        decl
        doc.FirstChild()ToDeclaration();
        然后就可以使用它的功能了,它可以让你返回当前的版本,编码等信息,函数原形如下:
        charVersion()Encoding()Standalone()

        在程序中你可以如下使用:

        ToDeclaration();
        cout
        使用TinyXml的声明对象(TiXmlDeclaration)输出声明对象对应的xml内容declPrint(0str);
        cout
        str分别输出声明对象的属性版本:是否为对立文件编码方式:endl;


        注释类
        这个类一般为xml数据提供解释说明,在程序中一般不使用它,因此,这里就不介绍了。

        元素类
        元素为一个容器类,它具有元素名称,并可以包含其它元素,文本,注释和未知节点,这些对象统称为元素的节点,即节点可以为元素、文本、注释和未知节点类型。元素也可以包含任意个数的属性
        我们还是以如下的XML代码来说明这个类的功能



        节点名
        在上方元素的代码中,element为根元素的名称,你可以通过如下的函数来设置和返回它。
        ValueStr()SetValue(_value)

        父节点
        subelement1,subelement2,subelement3,subelement4都是element的子元素,如果当前元素对象的指针指向subelement1,subelement2,subelement3,subelement4,你可以通过Parent()函数来返回指向element对象的指针,Parent()函数的声明如下:
        TiXmlNodeParent()

        子节点
        通过父节点的指针,你可以遍历所有的子节点。
        FirstChild()
        FirstChild(_value)
        上面两个函数用于返回第一个子节点对象的指针,带参数名的那个函数表示返回第一个名为_value的子节点。

        LastChild()
        LastChild(_value)
        上面的两个函数用于返回最后一个节点对象的指针,带参数名的那个函数表示返回最后一个名为_value的子节点。

        你也可以使用IterateChildren()函数来依次遍历所有的节点,它们的函数声明如下:
        IterateChildren(prevIoUs)
        _value,sans-serif; font-size:13px; line-height:19px">prevIoUs)
        带参数名的那个函数表示只遍历同名的节点。

        编辑子节点
        你可以插入、删除替换所有的子节点。
        InsertEndChild(addThis);
        InsertBeforeChild(TiXmlNodebeforeThis,sans-serif; font-size:13px; line-height:19px">InsertAfterChild(TiXmlNodeafterThis,sans-serif; font-size:13px; line-height:19px">addThis);
        上面三个函数用于插入节点,InsertEndChild函数让你把新节点插入到末尾,InsertBeforeChild和InsertAfterChild函数允许你在指定的节点位置前后插入节点。

        ReplaceChild(TiXmlNodereplaceThis,sans-serif; font-size:13px; line-height:19px">withThis);
        ReplaceChild函数用于替换指定的节点。

        RemoveChild(TiXmlNoderemoveThis);
        RemoveChild函数让你删除指定的节点。
        Clear();
        Clear函数删除本节点的所有子节点(包括子节点包含的从子节点),但不会修改本节点。

        同级节点


        在上面的xml代码中,subelement1、subelement2、subelement3、subelement4都属于同级节点,我们也提供了相关的函数用于在这些同级节点中遍历。

        PrevIoUsSibling()
        PrevIoUsSibling(_value)
        可以根据当前的节点,返回上一个节点的指针。带参数名的那个函数表示返回上一个名为_value的节点。

        当然你也可以根据当前的节点,返回下一个节点的指针。带参数名的那个函数表示返回下一个名为_value的节点。
        NextSibling()
        NextSibling(_value)

        遍历元素
        元素是一种特殊的节点,以’
        ’为开始字符,后接元素名称函数NextSiblingElement用于返回下一个同级元素,而忽略其它类型的节点。它们的函数声明如下:
        NextSiblingElement()
        NextSiblingElement(_value)
        带参数名的那个函数表示返回下一个名为_value的同级元素。

        本类也提供了相关的函数,让你返回第一个子元素。
        FirstChildElement()
        FirstChildElement(_value)
        带参数名的那个函数表示返回下一个名为_value的子元素。

        元素属性
        属性一般保存在元素中,它们为使用“
        ”号连接的两个字符串,左边的表示属性名,等号右边的表示属性值,通常使用字符串、整数和浮点数等数据类型表示。例如,pi
        你可以通过如下的函数,返回属性值。
        Attribute(name);
        name,sans-serif; font-size:13px; line-height:19px">i)doubled);
        在上面3个函数中,第一个函数使用字符串保存返回的属性值,第二个函数属性值转换为整数然后返回,第三个函数属性值转换为浮点数然后返回。不过,第二、三个函数都会以字符串的形式记录属性值,并作为函数的返回值返回。
        另外,你也可以使用模板函数
        templatetypenameTQueryValueAttribute(outValue)
        来返回特点的属性值,它会根据你传入的参数,自动选择合适数据类型。

        另外,本类也提供了如下三个函数让你设置属性,参数的类型和返回函数类似。
        _value);
        SetDoubleAttribute(value);

        FirstAttribute和LastAttribute可以让你返回第一个和最后一个属性,它们的函数声明如下:
        TiXmlAttributeFirstAttribute()
        LastAttribute()
        RemoveAttribute函数可以让你删除指定名称属性,它的函数声明如下:
        RemoveAttribute(name)

        元素函数总结
        ValueStr
        返回元素名称SetValue设置元素名称Parent返回父节点对象
        FirstChild
        返回第一个子节点LastChild返回最后一个子节点IterateChildren返回下一个子节点
        InsertEndChild
        在最后一个子节点后插入子节点InsertBeforeChild在指定的子节点前插入子节点InsertAfterChild在指定的子节点后插入子节点ReplaceChild替换指定的子节点RemoveChild删除指定的子节点Clear删除所有的子节点
        PrevIoUsSibling
        返回同级中前一个节点NextSibling返回同级中后一个节点
        NextSiblingElement
        返回同级中后一个元素FirstChildElement返回第一个子元素节点Attribute返回元素中的属性QueryValueAttributeSetAttribute设置元素中的属性FirstAttribute返回元素中第一个属性对象LastAttribute返回元素中最后一个属性对象RemoveAttribute删除元素中指定的属性对象
        属性
        属性名称
        对,元素可以具有属性值,但名称必须唯一。
        你可以通过
        NameTStr()
        返回属性名称

        也可以通过下面三个函数返回属性值:
        IntValue()DoubleValue();

        当然你也可以设置属性值,它们的函数声明如下:
        SetName(_name)
        SetIntValue(SetDoubleValue(_value)
        以上函数与元素类中的相关函数类似,这里不重复介绍了。

        在元素属性中,通常具有许多属性,你可以通过Next函数返回下一个属性对象的指针,也可以通过PrevIoUs函数获得上一个属性对象的指针。它们的函数声明如下:
        Next()
        PrevIoUs()

        相关文章

        引言 NOKIA 有句著名的广告语:“科技以人为本”。任何技术都是为了满足人的生产生活需要而产生的。具体...
        Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Reprint it anywhere u want. 文章...
        Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Reprint it anywhere u want. 文章...
        http://blog.jobbole.com/79252/ 引言 NOKIA 有句著名的广告语:“科技以人为本”。任何技术都是为了满...
        (点击上方公众号,可快速关注) 公众号:smart_android 作者:耿广龙|loonggg 点击“阅读原文”,可查看...
        一、xml与xslt 相信所有人对xml都不陌生,其被广泛的应用于数据数据传输、保存与序列化中,是一种极为强...