前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >XML实例

XML实例

作者头像
用户3519280
发布2023-07-06 14:58:41
1910
发布2023-07-06 14:58:41
举报
文章被收录于专栏:c++ 学习分享

XML实例

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

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

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

代码语言:javascript
复制
TiXmlDocument doc( "demo.xml" );  
doc.LoadFile(); 

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

代码语言:javascript
复制
// load the named file and dump its structure to STDOUT  
void dump_to_stdout(const char* pFilename)  
{  
    TiXmlDocument doc(pFilename);  
    bool loadOkay = doc.LoadFile();  
    if (loadOkay)  
    {  
        printf("\n%s:\n", pFilename);  
        dump_to_stdout( &doc ); // defined later 
}  
else  
{  
    printf("Failed to load file \"%s\"\n", pFilename);  
}   
写个简单的Main函数
int main(void)  
{  
    dump_to_stdout("example1.xml");  
    return 0;  
} 
读下面的文件
<?xml version="1.0" ?>  
<Hello>World</Hello> 
输出如下
DECLARATION  
+ ELEMENT Hello  
  + TEXT[World]  

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

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

代码语言:javascript
复制
void build_simple_doc( )  
{  
    // Make xml: <?xml ..><Hello>World</Hello>  
    TiXmlDocument doc;  
    TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );  
    TiXmlElement * element = new TiXmlElement( "Hello" );  
    TiXmlText * text = new TiXmlText( "World" );  
    element->LinkEndChild( text );  
    doc.LinkEndChild( decl );  
    doc.LinkEndChild( element );  
    doc.SaveFile( "madeByHand.xml" );  
}  

与其等价的写法:

代码语言:javascript
复制
void write_simple_doc2( )  
{  
    // same as write_simple_doc1 but add each node  
    // as early as possible into the tree.  
  
    TiXmlDocument doc;  
    TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );  
    doc.LinkEndChild( decl );  
      
    TiXmlElement * element = new TiXmlElement( "Hello" );  
    doc.LinkEndChild( element );  
      
    TiXmlText * text = new TiXmlText( "World" );  
    element->LinkEndChild( text );  
      
    doc.SaveFile( "madeByHand2.xml" );  
}  

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

代码语言:javascript
复制
window = new TiXmlElement( "Demo" );    
window->SetAttribute("name", "Circle");  
window->SetAttribute("x", 5);  
window->SetAttribute("y", 15);  
window->SetDoubleAttribute("radius", 3.14159); 

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

代码语言:javascript
复制
// print all attributes of pElement.  
// returns the number of attributes printed  
int dump_attribs_to_stdout(TiXmlElement* pElement, unsigned int indent)  
{  
    if ( !pElement ) return 0;  
  
    TiXmlAttribute* pAttrib=pElement->FirstAttribute();  
    int i=0;  
    int ival;  
    double dval;  
    const char* pIndent=getIndent(indent);  
    printf("\n");  
    while (pAttrib)  
    {  
        printf( "%s%s: value=[%s]", pIndent, pAttrib->Name(), pAttrib->Value());  
  
        if (pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS)    printf( " int=%d", ival);  
        if (pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) printf( " d=%1.1f", dval);  
        printf( "\n" );  
        i++;  
        pAttrib=pAttrib->Next();  
    }  
    return i;  
}  

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

代码语言:javascript
复制
#include <string>  
#include <map>  
using namespace std;  
  
typedef std::map<std::string,std::string> MessageMap;  
  
// a basic window abstraction - demo purposes only  
class WindowSettings  
{  
public:  
    int x,y,w,h;  
    string name;  
  
    WindowSettings()  
        : x(0), y(0), w(100), h(100), name("Untitled")  
    {  
    }  
  
    WindowSettings(int x, int y, int w, int h, const string& name)  
    {  
        this->x=x;  
        this->y=y;  
        this->w=w;  
        this->h=h;  
        this->name=name;  
    }  
};  
  
class ConnectionSettings  
{  
public:  
    string ip;  
    double timeout;  
};  
  
class AppSettings  
{  
public:  
    string m_name;  
    MessageMap m_messages;  
    list<WindowSettings> m_windows;  
    ConnectionSettings m_connection;  
  
    AppSettings() {}  
  
    void save(const char* pFilename);  
    void load(const char* pFilename);  
      
    // just to show how to do it  
    void setDemoValues()  
    {  
        m_name="MyApp";  
        m_messages.clear();  
        m_messages["Welcome"]="Welcome to "+m_name;  
        m_messages["Farewell"]="Thank you for using "+m_name;  
        m_windows.clear();  
        m_windows.push_back(WindowSettings(15,15,400,250,"Main"));  
        m_connection.ip="Unknown";  
        m_connection.timeout=123.456;  
    }  
};  

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

代码语言:javascript
复制
int main(void)  
{  
    AppSettings settings;  
      
    settings.save("appsettings2.xml");  
    settings.load("appsettings2.xml");  
    return 0;  
}  

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

代码语言:javascript
复制
int main(void)  
{  
    // block: customise and save settings  
    {  
        AppSettings settings;  
        settings.m_name="HitchHikerApp";  
        settings.m_messages["Welcome"]="Don't Panic";  
        settings.m_messages["Farewell"]="Thanks for all the fish";  
        settings.m_windows.push_back(WindowSettings(15,25,300,250,"BookFrame"));  
        settings.m_connection.ip="192.168.0.77";  
        settings.m_connection.timeout=42.0;  
  
        settings.save("appsettings2.xml");  
    }  
      
    // block: load settings  
    {  
        AppSettings settings;  
        settings.load("appsettings2.xml");  
        printf("%s: %s\n", settings.m_name.c_str(),   
            settings.m_messages["Welcome"].c_str());  
        WindowSettings & w=settings.m_windows.front();  
        printf("%s: Show window '%s' at %d,%d (%d x %d)\n",   
            settings.m_name.c_str(), w.name.c_str(), w.x, w.y, w.w, w.h);  
        printf("%s: %s\n", settings.m_name.c_str(), settings.m_messages["Farewell"].c_str());  
    }  
    return 0;  
}  

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

代码语言:javascript
复制
void AppSettings::save(const char* pFilename)  
{  
    TiXmlDocument doc;    
    TiXmlElement* msg;  
    TiXmlComment * comment;  
    string s;  
    TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" );    
    doc.LinkEndChild( decl );   
   
    TiXmlElement * root = new TiXmlElement(m_name.c_str());    
    doc.LinkEndChild( root );    
  
    comment = new TiXmlComment();  
    s=" Settings for "+m_name+" ";  
    comment->SetValue(s.c_str());    
    root->LinkEndChild( comment );    
  
    // block: messages  
    {  
        MessageMap::iterator iter;  
  
        TiXmlElement * msgs = new TiXmlElement( "Messages" );    
        root->LinkEndChild( msgs );    
   
        for (iter=m_messages.begin(); iter != m_messages.end(); iter++)  
        {  
            const string & key=(*iter).first;  
            const string & value=(*iter).second;  
            msg = new TiXmlElement(key.c_str());    
            msg->LinkEndChild( new TiXmlText(value.c_str()));    
            msgs->LinkEndChild( msg );    
        }  
    }  
  
    // block: windows  
    {  
        TiXmlElement * windowsNode = new TiXmlElement( "Windows" );    
        root->LinkEndChild( windowsNode );    
  
        list<WindowSettings>::iterator iter;  
  
        for (iter=m_windows.begin(); iter != m_windows.end(); iter++)  
        {  
            const WindowSettings& w=*iter;  
  
            TiXmlElement * window;  
            window = new TiXmlElement( "Window" );    
            windowsNode->LinkEndChild( window );    
            window->SetAttribute("name", w.name.c_str());  
            window->SetAttribute("x", w.x);  
            window->SetAttribute("y", w.y);  
            window->SetAttribute("w", w.w);  
            window->SetAttribute("h", w.h);  
        }  
    }  
  
    // block: connection  
    {  
        TiXmlElement * cxn = new TiXmlElement( "Connection" );    
        root->LinkEndChild( cxn );    
        cxn->SetAttribute("ip", m_connection.ip.c_str());  
        cxn->SetDoubleAttribute("timeout", m_connection.timeout);   
    }  
  
    doc.SaveFile(pFilename);    
}  

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

代码语言:javascript
复制
void AppSettings::load(const char* pFilename)  
{  
    TiXmlDocument doc(pFilename);  
    if (!doc.LoadFile()) return;  
  
    TiXmlHandle hDoc(&doc);  
    TiXmlElement* pElem;  
    TiXmlHandle hRoot(0);  
  
    // block: name  
    {  
        pElem=hDoc.FirstChildElement().Element();  
        // should always have a valid root but handle gracefully if it does  
        if (!pElem) return;  
        m_name=pElem->Value();  
  
        // save this for later  
        hRoot=TiXmlHandle(pElem);  
    }  
  
    // block: string table  
    {  
        m_messages.clear(); // trash existing table  
  
        pElem=hRoot.FirstChild( "Messages" ).FirstChild().Element();  
        for( pElem; pElem; pElem=pElem->NextSiblingElement())  
        {  
            const char *pKey=pElem->Value();  
            const char *pText=pElem->GetText();  
            if (pKey && pText)   
            {  
                m_messages[pKey]=pText;  
            }  
        }  
    }  
  
    // block: windows  
    {  
        m_windows.clear(); // trash existing list  
  
        TiXmlElement* pWindowNode=hRoot.FirstChild( "Windows" ).FirstChild().Element();  
        for( pWindowNode; pWindowNode; pWindowNode=pWindowNode->NextSiblingElement())  
        {  
            WindowSettings w;  
            const char *pName=pWindowNode->Attribute("name");  
            if (pName) w.name=pName;  
              
            pWindowNode->QueryIntAttribute("x", &w.x); // If this fails, original value is left as-is  
            pWindowNode->QueryIntAttribute("y", &w.y);  
            pWindowNode->QueryIntAttribute("w", &w.w);  
            pWindowNode->QueryIntAttribute("hh", &w.h);  
  
            m_windows.push_back(w);  
        }  
    }  
  
    // block: connection  
    {  
        pElem=hRoot.FirstChild("Connection").Element();  
        if (pElem)  
        {  
            m_connection.ip=pElem->Attribute("ip");  
            pElem->QueryDoubleAttribute("timeout",&m_connection.timeout);  
        }  
    }  
}  
函数dump_to_stdout如下:
代码语言:javascript
复制
#include "stdafx.h"  
#include "tinyxml.h"  
  
// ----------------------------------------------------------------------  
// STDOUT dump and indenting utility functions  
// ----------------------------------------------------------------------  
const unsigned int NUM_INDENTS_PER_SPACE=2;  
  
const char * getIndent( unsigned int numIndents )  
{  
    static const char * pINDENT="                                      + ";  
    static const unsigned int LENGTH=strlen( pINDENT );  
    unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;  
    if ( n > LENGTH ) n = LENGTH;  
  
    return &pINDENT[ LENGTH-n ];  
}  
  
// same as getIndent but no "+" at the end  
const char * getIndentAlt( unsigned int numIndents )  
{  
    static const char * pINDENT="                                        ";  
    static const unsigned int LENGTH=strlen( pINDENT );  
    unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;  
    if ( n > LENGTH ) n = LENGTH;  
  
    return &pINDENT[ LENGTH-n ];  
}  
  
int dump_attribs_to_stdout(TiXmlElement* pElement, unsigned int indent)  
{  
    if ( !pElement ) return 0;  
  
    TiXmlAttribute* pAttrib=pElement->FirstAttribute();  
    int i=0;  
    int ival;  
    double dval;  
    const char* pIndent=getIndent(indent);  
    printf("\n");  
    while (pAttrib)  
    {  
        printf( "%s%s: value=[%s]", pIndent, pAttrib->Name(), pAttrib->Value());  
  
        if (pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS)    printf( " int=%d", ival);  
        if (pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) printf( " d=%1.1f", dval);  
        printf( "\n" );  
        i++;  
        pAttrib=pAttrib->Next();  
    }  
    return i;     
}  
  
void dump_to_stdout( TiXmlNode* pParent, unsigned int indent = 0 )  
{  
    if ( !pParent ) return;  
  
    TiXmlNode* pChild;  
    TiXmlText* pText;  
    int t = pParent->Type();  
    printf( "%s", getIndent(indent));  
    int num;  
  
    switch ( t )  
    {  
    case TiXmlNode::TINYXML_DOCUMENT:  
        printf( "Document" );  
        break;  
  
    case TiXmlNode::TINYXML_ELEMENT:  
        printf( "Element [%s]", pParent->Value() );  
        num=dump_attribs_to_stdout(pParent->ToElement(), indent+1);  
        switch(num)  
        {  
            case 0:  printf( " (No attributes)"); break;  
            case 1:  printf( "%s1 attribute", getIndentAlt(indent)); break;  
            default: printf( "%s%d attributes", getIndentAlt(indent), num); break;  
        }  
        break;  
  
    case TiXmlNode::TINYXML_COMMENT:  
        printf( "Comment: [%s]", pParent->Value());  
        break;  
  
    case TiXmlNode::TINYXML_UNKNOWN:  
        printf( "Unknown" );  
        break;  
  
    case TiXmlNode::TINYXML_TEXT:  
        pText = pParent->ToText();  
        printf( "Text: [%s]", pText->Value() );  
        break;  
  
    case TiXmlNode::TINYXML_DECLARATION:  
        printf( "Declaration" );  
        break;  
    default:  
        break;  
    }  
    printf( "\n" );  
    for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())   
    {  
        dump_to_stdout( pChild, indent+1 );  
    }  
}  
  
// load the named file and dump its structure to STDOUT  
void dump_to_stdout(const char* pFilename)  
{  
    TiXmlDocument doc(pFilename);  
    bool loadOkay = doc.LoadFile();  
    if (loadOkay)  
    {  
        printf("\n%s:\n", pFilename);  
        dump_to_stdout( &doc ); // defined later in the tutorial  
    }  
    else  
    {  
        printf("Failed to load file \"%s\"\n", pFilename);  
    }  
}  

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-10-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • XML实例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档