zoukankan      html  css  js  c++  java
  • XML实例

    TinyXML是一个非常小巧简单的XML解析库,采用DOM方式来解析XML文件。不足的是它本身不支持DTD和XSL,但普通简单的XML使用需求还是可以满足了。

    TinyXML由2个头文件四个CPP文件构成。继承结构如下:

    要操作XML首先需要加载XML,很简单:

    1. TiXmlDocument doc( "demo.xml" );  
    2. doc.LoadFile();  

    一个更加真实的用例如下所示,加载一个XML文件然后显示内容到标准输出上。

    1. // load the named file and dump its structure to STDOUT  
    2. void dump_to_stdout(const char* pFilename)  
    3. {  
    4.     TiXmlDocument doc(pFilename);  
    5.     bool loadOkay = doc.LoadFile();  
    6.     if (loadOkay)  
    7.     {  
    8.         printf("\n%s:\n", pFilename);  
    9.         dump_to_stdout( &doc ); // defined later  
    1. }  
    2. else  
    3. {  
    4.     printf("Failed to load file \"%s\"\n", pFilename);  
    5. }  

    写个简单的Main函数

    1. int main(void)  
    2. {  
    3.     dump_to_stdout("example1.xml");  
    4.     return 0;  
    5. }  


    读下面的文件

    1. <?xml version="1.0" ?>  
    2. <Hello>World</Hello>  

    输出如下

    1. DECLARATION  
    2. + ELEMENT Hello  
    3.   + TEXT[World]  

    dump_to_stdout递归遍历输出所有的XML内容,详细实现在本文的末尾。

    TinyXML同样可以简单的编程生成一个上面的XML:

    1. void build_simple_doc( )  
    2. {  
    3.     // Make xml: <?xml ..><Hello>World</Hello>  
    4.     TiXmlDocument doc;  
    5.     TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0""""" );  
    6.     TiXmlElement * element = new TiXmlElement( "Hello" );  
    7.     TiXmlText * text = new TiXmlText( "World" );  
    8.     element->LinkEndChild( text );  
    9.     doc.LinkEndChild( decl );  
    10.     doc.LinkEndChild( element );  
    11.     doc.SaveFile( "madeByHand.xml" );  
    12. }  

    与其等价的写法:

    1. void write_simple_doc2( )  
    2. {  
    3.     // same as write_simple_doc1 but add each node  
    4.     // as early as possible into the tree.  
    5.   
    6.     TiXmlDocument doc;  
    7.     TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0""""" );  
    8.     doc.LinkEndChild( decl );  
    9.       
    10.     TiXmlElement * element = new TiXmlElement( "Hello" );  
    11.     doc.LinkEndChild( element );  
    12.       
    13.     TiXmlText * text = new TiXmlText( "World" );  
    14.     element->LinkEndChild( text );  
    15.       
    16.     doc.SaveFile( "madeByHand2.xml" );  
    17. }  

    给定一个节点,设置它的属性也很简单:

    1. window = new TiXmlElement( "Demo" );    
    2. window->SetAttribute("name""Circle");  
    3. window->SetAttribute("x", 5);  
    4. window->SetAttribute("y", 15);  
    5. window->SetDoubleAttribute("radius", 3.14159);  

    可以用下面的函数获得元素的所有属性:

    1. // print all attributes of pElement.  
    2. // returns the number of attributes printed  
    3. int dump_attribs_to_stdout(TiXmlElement* pElement, unsigned int indent)  
    4. {  
    5.     if ( !pElement ) return 0;  
    6.   
    7.     TiXmlAttribute* pAttrib=pElement->FirstAttribute();  
    8.     int i=0;  
    9.     int ival;  
    10.     double dval;  
    11.     const char* pIndent=getIndent(indent);  
    12.     printf("\n");  
    13.     while (pAttrib)  
    14.     {  
    15.         printf( "%s%s: value=[%s]", pIndent, pAttrib->Name(), pAttrib->Value());  
    16.   
    17.         if (pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS)    printf( " int=%d", ival);  
    18.         if (pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) printf( " d=%1.1f", dval);  
    19.         printf( "\n" );  
    20.         i++;  
    21.         pAttrib=pAttrib->Next();  
    22.     }  
    23.     return i;  
    24. }  

    我们经常通过配置文件来保存程序的一些配置信息。下面给一个实例来用XML加载和保存C++对象。

    1. #include <string>  
    2. #include <map>  
    3. using namespace std;  
    4.   
    5. typedef std::map<std::string,std::string> MessageMap;  
    6.   
    7. // a basic window abstraction - demo purposes only  
    8. class WindowSettings  
    9. {  
    10. public:  
    11.     int x,y,w,h;  
    12.     string name;  
    13.   
    14.     WindowSettings()  
    15.         : x(0), y(0), w(100), h(100), name("Untitled")  
    16.     {  
    17.     }  
    18.   
    19.     WindowSettings(int x, int y, int w, int h, const string& name)  
    20.     {  
    21.         this->x=x;  
    22.         this->y=y;  
    23.         this->w=w;  
    24.         this->h=h;  
    25.         this->name=name;  
    26.     }  
    27. };  
    28.   
    29. class ConnectionSettings  
    30. {  
    31. public:  
    32.     string ip;  
    33.     double timeout;  
    34. };  
    35.   
    36. class AppSettings  
    37. {  
    38. public:  
    39.     string m_name;  
    40.     MessageMap m_messages;  
    41.     list<WindowSettings> m_windows;  
    42.     ConnectionSettings m_connection;  
    43.   
    44.     AppSettings() {}  
    45.   
    46.     void save(const char* pFilename);  
    47.     void load(const char* pFilename);  
    48.       
    49.     // just to show how to do it  
    50.     void setDemoValues()  
    51.     {  
    52.         m_name="MyApp";  
    53.         m_messages.clear();  
    54.         m_messages["Welcome"]="Welcome to "+m_name;  
    55.         m_messages["Farewell"]="Thank you for using "+m_name;  
    56.         m_windows.clear();  
    57.         m_windows.push_back(WindowSettings(15,15,400,250,"Main"));  
    58.         m_connection.ip="Unknown";  
    59.         m_connection.timeout=123.456;  
    60.     }  
    61. };  

    类AppSettings提供了保存和加载配置信息的函数save和load。如下代码表示利用缺省的配置保存和加载:

    1. int main(void)  
    2. {  
    3.     AppSettings settings;  
    4.       
    5.     settings.save("appsettings2.xml");  
    6.     settings.load("appsettings2.xml");  
    7.     return 0;  
    8. }  

    同样的我们可以运行时修改配置:

    1. int main(void)  
    2. {  
    3.     // block: customise and save settings  
    4.     {  
    5.         AppSettings settings;  
    6.         settings.m_name="HitchHikerApp";  
    7.         settings.m_messages["Welcome"]="Don't Panic";  
    8.         settings.m_messages["Farewell"]="Thanks for all the fish";  
    9.         settings.m_windows.push_back(WindowSettings(15,25,300,250,"BookFrame"));  
    10.         settings.m_connection.ip="192.168.0.77";  
    11.         settings.m_connection.timeout=42.0;  
    12.   
    13.         settings.save("appsettings2.xml");  
    14.     }  
    15.       
    16.     // block: load settings  
    17.     {  
    18.         AppSettings settings;  
    19.         settings.load("appsettings2.xml");  
    20.         printf("%s: %s\n", settings.m_name.c_str(),   
    21.             settings.m_messages["Welcome"].c_str());  
    22.         WindowSettings & w=settings.m_windows.front();  
    23.         printf("%s: Show window '%s' at %d,%d (%d x %d)\n",   
    24.             settings.m_name.c_str(), w.name.c_str(), w.x, w.y, w.w, w.h);  
    25.         printf("%s: %s\n", settings.m_name.c_str(), settings.m_messages["Farewell"].c_str());  
    26.     }  
    27.     return 0;  
    28. }  

    有很多方法可以保存对象的属性信息,也就是对象的状态信息。下面的实例展示如何将对象的状态编码进XML文件。

    1. void AppSettings::save(const char* pFilename)  
    2. {  
    3.     TiXmlDocument doc;    
    4.     TiXmlElement* msg;  
    5.     TiXmlComment * comment;  
    6.     string s;  
    7.     TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0""""" );    
    8.     doc.LinkEndChild( decl );   
    9.    
    10.     TiXmlElement * root = new TiXmlElement(m_name.c_str());    
    11.     doc.LinkEndChild( root );    
    12.   
    13.     comment = new TiXmlComment();  
    14.     s=" Settings for "+m_name+" ";  
    15.     comment->SetValue(s.c_str());    
    16.     root->LinkEndChild( comment );    
    17.   
    18.     // block: messages  
    19.     {  
    20.         MessageMap::iterator iter;  
    21.   
    22.         TiXmlElement * msgs = new TiXmlElement( "Messages" );    
    23.         root->LinkEndChild( msgs );    
    24.    
    25.         for (iter=m_messages.begin(); iter != m_messages.end(); iter++)  
    26.         {  
    27.             const string & key=(*iter).first;  
    28.             const string & value=(*iter).second;  
    29.             msg = new TiXmlElement(key.c_str());    
    30.             msg->LinkEndChild( new TiXmlText(value.c_str()));    
    31.             msgs->LinkEndChild( msg );    
    32.         }  
    33.     }  
    34.   
    35.     // block: windows  
    36.     {  
    37.         TiXmlElement * windowsNode = new TiXmlElement( "Windows" );    
    38.         root->LinkEndChild( windowsNode );    
    39.   
    40.         list<WindowSettings>::iterator iter;  
    41.   
    42.         for (iter=m_windows.begin(); iter != m_windows.end(); iter++)  
    43.         {  
    44.             const WindowSettings& w=*iter;  
    45.   
    46.             TiXmlElement * window;  
    47.             window = new TiXmlElement( "Window" );    
    48.             windowsNode->LinkEndChild( window );    
    49.             window->SetAttribute("name", w.name.c_str());  
    50.             window->SetAttribute("x", w.x);  
    51.             window->SetAttribute("y", w.y);  
    52.             window->SetAttribute("w", w.w);  
    53.             window->SetAttribute("h", w.h);  
    54.         }  
    55.     }  
    56.   
    57.     // block: connection  
    58.     {  
    59.         TiXmlElement * cxn = new TiXmlElement( "Connection" );    
    60.         root->LinkEndChild( cxn );    
    61.         cxn->SetAttribute("ip", m_connection.ip.c_str());  
    62.         cxn->SetDoubleAttribute("timeout", m_connection.timeout);   
    63.     }  
    64.   
    65.     doc.SaveFile(pFilename);    
    66. }  

    下面的示例展示如何从XML文件中获得对象的状态信息:

    1. void AppSettings::load(const char* pFilename)  
    2. {  
    3.     TiXmlDocument doc(pFilename);  
    4.     if (!doc.LoadFile()) return;  
    5.   
    6.     TiXmlHandle hDoc(&doc);  
    7.     TiXmlElement* pElem;  
    8.     TiXmlHandle hRoot(0);  
    9.   
    10.     // block: name  
    11.     {  
    12.         pElem=hDoc.FirstChildElement().Element();  
    13.         // should always have a valid root but handle gracefully if it does  
    14.         if (!pElem) return;  
    15.         m_name=pElem->Value();  
    16.   
    17.         // save this for later  
    18.         hRoot=TiXmlHandle(pElem);  
    19.     }  
    20.   
    21.     // block: string table  
    22.     {  
    23.         m_messages.clear(); // trash existing table  
    24.   
    25.         pElem=hRoot.FirstChild( "Messages" ).FirstChild().Element();  
    26.         for( pElem; pElem; pElem=pElem->NextSiblingElement())  
    27.         {  
    28.             const char *pKey=pElem->Value();  
    29.             const char *pText=pElem->GetText();  
    30.             if (pKey && pText)   
    31.             {  
    32.                 m_messages[pKey]=pText;  
    33.             }  
    34.         }  
    35.     }  
    36.   
    37.     // block: windows  
    38.     {  
    39.         m_windows.clear(); // trash existing list  
    40.   
    41.         TiXmlElement* pWindowNode=hRoot.FirstChild( "Windows" ).FirstChild().Element();  
    42.         for( pWindowNode; pWindowNode; pWindowNode=pWindowNode->NextSiblingElement())  
    43.         {  
    44.             WindowSettings w;  
    45.             const char *pName=pWindowNode->Attribute("name");  
    46.             if (pName) w.name=pName;  
    47.               
    48.             pWindowNode->QueryIntAttribute("x", &w.x); // If this fails, original value is left as-is  
    49.             pWindowNode->QueryIntAttribute("y", &w.y);  
    50.             pWindowNode->QueryIntAttribute("w", &w.w);  
    51.             pWindowNode->QueryIntAttribute("hh", &w.h);  
    52.   
    53.             m_windows.push_back(w);  
    54.         }  
    55.     }  
    56.   
    57.     // block: connection  
    58.     {  
    59.         pElem=hRoot.FirstChild("Connection").Element();  
    60.         if (pElem)  
    61.         {  
    62.             m_connection.ip=pElem->Attribute("ip");  
    63.             pElem->QueryDoubleAttribute("timeout",&m_connection.timeout);  
    64.         }  
    65.     }  
    66. }  

    函数dump_to_stdout如下:

    1. #include "stdafx.h"  
    2. #include "tinyxml.h"  
    3.   
    4. // ----------------------------------------------------------------------  
    5. // STDOUT dump and indenting utility functions  
    6. // ----------------------------------------------------------------------  
    7. const unsigned int NUM_INDENTS_PER_SPACE=2;  
    8.   
    9. const char * getIndent( unsigned int numIndents )  
    10. {  
    11.     static const char * pINDENT="                                      + ";  
    12.     static const unsigned int LENGTH=strlen( pINDENT );  
    13.     unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;  
    14.     if ( n > LENGTH ) n = LENGTH;  
    15.   
    16.     return &pINDENT[ LENGTH-n ];  
    17. }  
    18.   
    19. // same as getIndent but no "+" at the end  
    20. const char * getIndentAlt( unsigned int numIndents )  
    21. {  
    22.     static const char * pINDENT="                                        ";  
    23.     static const unsigned int LENGTH=strlen( pINDENT );  
    24.     unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;  
    25.     if ( n > LENGTH ) n = LENGTH;  
    26.   
    27.     return &pINDENT[ LENGTH-n ];  
    28. }  
    29.   
    30. int dump_attribs_to_stdout(TiXmlElement* pElement, unsigned int indent)  
    31. {  
    32.     if ( !pElement ) return 0;  
    33.   
    34.     TiXmlAttribute* pAttrib=pElement->FirstAttribute();  
    35.     int i=0;  
    36.     int ival;  
    37.     double dval;  
    38.     const char* pIndent=getIndent(indent);  
    39.     printf("\n");  
    40.     while (pAttrib)  
    41.     {  
    42.         printf( "%s%s: value=[%s]", pIndent, pAttrib->Name(), pAttrib->Value());  
    43.   
    44.         if (pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS)    printf( " int=%d", ival);  
    45.         if (pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) printf( " d=%1.1f", dval);  
    46.         printf( "\n" );  
    47.         i++;  
    48.         pAttrib=pAttrib->Next();  
    49.     }  
    50.     return i;     
    51. }  
    52.   
    53. void dump_to_stdout( TiXmlNode* pParent, unsigned int indent = 0 )  
    54. {  
    55.     if ( !pParent ) return;  
    56.   
    57.     TiXmlNode* pChild;  
    58.     TiXmlText* pText;  
    59.     int t = pParent->Type();  
    60.     printf( "%s", getIndent(indent));  
    61.     int num;  
    62.   
    63.     switch ( t )  
    64.     {  
    65.     case TiXmlNode::TINYXML_DOCUMENT:  
    66.         printf( "Document" );  
    67.         break;  
    68.   
    69.     case TiXmlNode::TINYXML_ELEMENT:  
    70.         printf( "Element [%s]", pParent->Value() );  
    71.         num=dump_attribs_to_stdout(pParent->ToElement(), indent+1);  
    72.         switch(num)  
    73.         {  
    74.             case 0:  printf( " (No attributes)"); break;  
    75.             case 1:  printf( "%s1 attribute", getIndentAlt(indent)); break;  
    76.             default: printf( "%s%d attributes", getIndentAlt(indent), num); break;  
    77.         }  
    78.         break;  
    79.   
    80.     case TiXmlNode::TINYXML_COMMENT:  
    81.         printf( "Comment: [%s]", pParent->Value());  
    82.         break;  
    83.   
    84.     case TiXmlNode::TINYXML_UNKNOWN:  
    85.         printf( "Unknown" );  
    86.         break;  
    87.   
    88.     case TiXmlNode::TINYXML_TEXT:  
    89.         pText = pParent->ToText();  
    90.         printf( "Text: [%s]", pText->Value() );  
    91.         break;  
    92.   
    93.     case TiXmlNode::TINYXML_DECLARATION:  
    94.         printf( "Declaration" );  
    95.         break;  
    96.     default:  
    97.         break;  
    98.     }  
    99.     printf( "\n" );  
    100.     for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())   
    101.     {  
    102.         dump_to_stdout( pChild, indent+1 );  
    103.     }  
    104. }  
    105.   
    106. // load the named file and dump its structure to STDOUT  
    107. void dump_to_stdout(const char* pFilename)  
    108. {  
    109.     TiXmlDocument doc(pFilename);  
    110.     bool loadOkay = doc.LoadFile();  
    111.     if (loadOkay)  
    112.     {  
    113.         printf("\n%s:\n", pFilename);  
    114.         dump_to_stdout( &doc ); // defined later in the tutorial  
    115.     }  
    116.     else  
    117.     {  
    118.         printf("Failed to load file \"%s\"\n", pFilename);  
    119.     }  
    120. }  


    如果你想在MFC中使用TinyXML,会出现这样的编译错误 fatal error C1010: unexpected end of file while looking for precompiled header。因为预编译头文件通过编译stdafx.cpp生成,可以在4个实现CPP文件中引入头#include   "stdafx.h"。记得放在最前面。这样就可以编译通过了。

  • 相关阅读:
    hdu 1875 Krustal最小生成树
    寒假学习PID和latex随笔2013/2/10
    HDU:今年暑假不AC
    HDU:七夕节
    寒假规划
    HDU:开门人和关门人
    HDU:cake
    HDU:最小公倍数
    HDU:Who's in the Middle
    Latex 第一个程序 效果
  • 原文地址:https://www.cnblogs.com/cy568searchx/p/2854841.html
Copyright © 2011-2022 走看看