TinyXml 指南 V2.60

TinyXML指南

 

目录:

这是什么

开始之前

开始

  从文件加载XML

  程序生成文档

  属性

  将文档写入文件

XML与C++的转化

  介绍

  构造你的对象类型

  将C++编码为XML

  从XML解析出C++

  dump_to_stdout 函数完整内容

 

  

TinyXML是什么

  本教程有一些有关如何有效使用TinyXML的提示和建议。

  我也试图包括一些C ++提示,例如如何将字符串转换为整数,反之亦然。这与TinyXML本身无关,但它可能对您的项目有帮助,所以我就这样做了。

  如果你不知道基本的C ++概念,本教程将不会对你有帮助。同样,如果你不知道什么是DOM,还是先去别处看看吧。

开始之前

将使用一些示例XML数据集/文件。

 

example1.xml:

<?xml version="1.0" ?>
<Hello>World</Hello>

example2.xml

<?xml version="1.0" ?>
<poetry>
        <verse>
                Alas
                  Great World
                        Alas (again)
        </verse>
 </poetry>

example3.xml:

<?xml version="1.0" ?>
<shapes>
       <circle name="int-based" x="20" y="30" r="50" />
       <point name="float-based" x="3.5" y="52.1" />
</shapes>

example4.xml:

<?xml version="1.0" ?>
<MyApp>
     <!-- Settings for MyApp -->
     <Messages>
         <Welcome>Welcome to MyApp</Welcome>
         <Farewell>Thank you for using MyApp</Farewell>
     </Messages>
     <Windows>
         <Window name="MainFrame" x="5" y="15" w="400" h="250" />
     </Windows>
     <Connection ip="192.168.0.1" timeout="123.456000" />
</MyApp>

 

开始

从文件加载XML

将文件加载进TinyXML DOM的最简单的方法是:

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

 

更真实的用法如下所示。这将加载文件并显示内容到STDOUT

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

 

这个函数的一个简单的示例是使用如下的main函数:

int main(void)
{
       dump_to_stdout("example1.xml");
       return 0;
}

回看Example 1 XML 如下:

<?xml version="1.0" ?>
<Hello>World</Hello>

使用此XML运行程序将在控制台/ DOS窗口中显示:

DOCUMENT
+ DECLARATION
+ ELEMENT Hello
  + TEXT[World]

 

dump_to_stdout 函数在本教程的后面定义,如果你想理解DOM的递归遍历,它是有用的。

 

 

程序化生成文档

程序化的生成 Example 1

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

这可以加载并显示在控制台上:

dump_to_stdout("madeByHand.xml"); // this func defined later in the tutorial

您将看到它与示例1相同:

madeByHand.xml:
Document
+ Declaration
+ Element [Hello]
  + Text: [World]

 

此代码生成完全相同的XML DOM,但它不同的顺序创建和链接节点:

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

这两个产生相同的XML,即:

<?xml version="1.0" ?>
<Hello>World</Hello>

或者相同的结构:

DOCUMENT
+ DECLARATION
+ ELEMENT Hello
  + TEXT[World]

 

 

属性

给定一个存在的节点,设置属性很容易:

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

 

你也可以使用TiXmlAttribute对象。

以下代码显示了获取元素的所有属性的一种方式(而不是唯一的方式),打印名称和字符串值,如果值可以转换为整数或双精度值,则还要打印该值:

// 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;
}

 

 

将文档写入文件

将预构建的DOM写入文件很简单:

doc.SaveFile( saveFilename ); 

 

回顾一下,比如example4.xml

<?xml version="1.0" ?>
<MyApp>
    <!-- Settings for MyApp -->
    <Messages>
        <Welcome>Welcome to MyApp</Welcome>
        <Farewell>Thank you for using MyApp</Farewell>
    </Messages>
    <Windows>
        <Window name="MainFrame" x="5" y="15" w="400" h="250" />
    </Windows>
    <Connection ip="192.168.0.1" timeout="123.456000" />
</MyApp>

 

以下函数构建此DOM并写入文件“appsettings.xml”

void write_app_settings_doc( ) 
{ 
       TiXmlDocument doc; 
       TiXmlElement* msg;
        TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" ); 
       doc.LinkEndChild( decl ); 
 
       TiXmlElement * root = new TiXmlElement( "MyApp" ); 
       doc.LinkEndChild( root ); 
 
       TiXmlComment * comment = new TiXmlComment();
       comment->SetValue(" Settings for MyApp " ); 
       root->LinkEndChild( comment ); 
 
       TiXmlElement * msgs = new TiXmlElement( "Messages" ); 
       root->LinkEndChild( msgs ); 
 
       msg = new TiXmlElement( "Welcome" ); 
       msg->LinkEndChild( new TiXmlText( "Welcome to MyApp" )); 
       msgs->LinkEndChild( msg ); 
 
       msg = new TiXmlElement( "Farewell" ); 
       msg->LinkEndChild( new TiXmlText( "Thank you for using MyApp" )); 
       msgs->LinkEndChild( msg ); 
 
       TiXmlElement * windows = new TiXmlElement( "Windows" ); 
       root->LinkEndChild( windows ); 
 
       TiXmlElement * window;
       window = new TiXmlElement( "Window" ); 
       windows->LinkEndChild( window ); 
       window->SetAttribute("name", "MainFrame");
       window->SetAttribute("x", 5);
       window->SetAttribute("y", 15);
       window->SetAttribute("w", 400);
       window->SetAttribute("h", 250);
 
       TiXmlElement * cxn = new TiXmlElement( "Connection" ); 
       root->LinkEndChild( cxn ); 
       cxn->SetAttribute("ip", "192.168.0.1");
       cxn->SetDoubleAttribute("timeout", 123.456); // floating point attrib
      
       dump_to_stdout( &doc );
       doc.SaveFile( "appsettings.xml" ); 
}

 

dump_to_stdout函数将显示此结构:

Document
+ Declaration
+ Element [MyApp]
 (No attributes)
  + Comment: [ Settings for MyApp ]
  + Element [Messages]
 (No attributes)
    + Element [Welcome]
 (No attributes)
      + Text: [Welcome to MyApp]
    + Element [Farewell]
 (No attributes)
      + Text: [Thank you for using MyApp]
  + Element [Windows]
 (No attributes)
    + Element [Window]
      + name: value=[MainFrame]
      + x: value=[5] int=5 d=5.0
      + y: value=[15] int=15 d=15.0
      + w: value=[400] int=400 d=400.0
      + h: value=[250] int=250 d=250.0
      5 attributes
  + Element [Connection]
    + ip: value=[192.168.0.1] int=192 d=192.2
    + timeout: value=[123.456000] int=123 d=123.5
    2 attributes

 

  让我感到惊讶的是,相对其他APITinyXml默认以一种很美观的格式输出XML——它对包含其他节点得元素的文本中的空白做了改动,这样写出的树包含对嵌套级别的呈现。

  我还没有见过一种写文件的时候关闭缩进的方法,显然这样很容易遇到麻烦。

【注:在STL模式仅需使用cout << myDoc。非STL模式总是使用漂亮的格式。添加一个开关将是一个很好的功能,并已被要求这样做。】

XML C++ 对象之间的转化

介绍

  此示例假设您正在将应用设置加载并保存在XML文件中,例如example4.xml

  有很多方法可以做到这一点。例如,访问  http://sourceforge.net/projects/tinybind 查看 TinyBind 项目。

  本节介绍一种使用XML加载和保存基本对象结构的简单方法。

构造你的对象类型

从一些基本类开始,如:

#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;
       }
};

 

这是一个基本的main(),展示如何创建默认设置对象树,保存它并重新加载:

int main(void)
{
       AppSettings settings;
      
       settings.save("appsettings2.xml");
       settings.load("appsettings2.xml");
       return 0;
}

 

下面的main() 展示了如何 创建、修改、保存,然后加载一个设置结构:

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

 

save()和load()完成(见下文)时,运行main()在控制台上显示:

HitchHikerApp: Don't Panic
HitchHikerApp: Show window 'BookFrame' at 15,25 (300 x 100)
HitchHikerApp: Thanks for all the fish

 

从C++状态编码为XML

有很多不同的方法来保存到一个文件。这里有一个:

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

 

运行修改后的main会生成如下文件:

<?xml version="1.0" ?>
<HitchHikerApp>
    <!-- Settings for HitchHikerApp -->
    <Messages>
        <Farewell>Thanks for all the fish</Farewell>
        <Welcome>Don&apos;t Panic</Welcome>
    </Messages>
    <Windows>
        <Window name="BookFrame" x="15" y="25" w="300" h="250" />
    </Windows>
    <Connection ip="192.168.0.77" timeout="42.000000" />
</HitchHikerApp>

 

从XML解码出C++状态

与编码对象进行编码一样,有许多方法可以将XML解码为您自己的C ++对象结构。以下方法使用TiXmlHandles

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 的完整列表

下面是一个可以复制粘贴的示例程序:加载XML文件,并使用上面列出的递归遍历将结构输出到STDOUT

// tutorial demo program
#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::DOCUMENT:
               printf( "Document" );
               break;
 
       case TiXmlNode::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::COMMENT:
               printf( "Comment: [%s]", pParent->Value());
               break;
 
       case TiXmlNode::UNKNOWN:
               printf( "Unknown" );
               break;
 
       case TiXmlNode::TEXT:
               pText = pParent->ToText();
               printf( "Text: [%s]", pText->Value() );
               break;
 
       case TiXmlNode::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);
       }
}
 
// ----------------------------------------------------------------------
// main() for printing files named on the command line
// ----------------------------------------------------------------------
int main(int argc, char* argv[])
{
       for (int i=1; i<argc; i++)
       {
               dump_to_stdout(argv[i]);
       }
       return 0;
}
View Code

 

从命令行或DOS窗口运行此命令,例如:

C:\dev\tinyxml> Debug\tinyxml_1.exe example1.xml
 
example1.xml:
Document
+ Declaration
+ Element [Hello]
 (No attributes)
  + Text: [World]

 

 

 

 

 

转载于:https://www.cnblogs.com/Yu-900914/articles/6592584.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值