游戏配置之XML

游戏开发中配置文件主要有ini个xml,xml用的更多些。

我用的较多的库是tinyXML,一般应用已足矣胜任,网上教程一大堆,就不写了。再次介绍另一个xml库,转载的其他人的blog的文章。

目前我公司开发的Nexus Engine的底层对象序列化使用了TinyXML来读写XML文件。TinyXML有两个不爽的地方,一是它的接口使用FILE*,另外一个是它对 wchar_t不能很好的支持。前阵子看Boost库的更新中多了一个PropertyTree,他在处理XML时用到了另外一个小的库 --RapidXML。既然间接的是Boost库的一部分,所以是值得一试的。于是找到其官方网站(http://rapidxml.sourceforge.net/ )研究了一番。一看之下,甚是满意,也推荐给大家看看!

    首先就是速度,据它自己宣称比TinyXML快30到60倍 ,比Xerces DOM快50到100倍!详细的测试比较请见其用户手册(http://rapidxml.sourceforge.net/manual.html )的“4. Performance ”一节。

其次它的设计非常的简洁,只依赖于标准库中的几个基本的类。它的输入输出都是字符串,这样很好,一个库就应该关注自己核心的内容,做尽量少的事情。它的API其实和TinyXML倒是有几分相似,用过TinyXML的人应该很容易上手:

TinyXML主要接口类 RapidXML的主要接口类
class TiXmlDocument template
   class xml_document

class TiXmlNode template
    class xml_node

class TiXmlAttribute template
    class xml_attribute

下面还是看一个具体的例子来体验一下,下面是TinyXML官方教程中创建XML文档的一段代码:

view plaincopy to clipboardprint?
void build_simple_doc( )  
{  
    // Make xml: World  
    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" );  
}
void build_simple_doc( )
{
    // Make xml: World
    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" );
}


下面是使用RapidXML实现类似功能的代码:

view plaincopy to clipboardprint?
void build_simple_doc_by_rapidxml()  
{  
    xml_document<> doc;  
    xml_node<>* decl = doc.allocate_node(node_declaration);  
    xml_attribute<>* decl_ver =  
        doc.allocate_attribute("version", "1.0");  
    decl->append_attribute(decl_ver);  
    doc.append_node(decl);  
    xml_node<>* node =  
        doc.allocate_node(node_element,    "Hello", "World");  
    doc.append_node(node);  
    string text;  
    rapidxml::print(std::back_inserter(text), doc, 0);  
    // write text to file by yourself  
}
    void build_simple_doc_by_rapidxml()
    {
        xml_document<> doc;
        xml_node<>* decl = doc.allocate_node(node_declaration);
        xml_attribute<>* decl_ver =
            doc.allocate_attribute("version", "1.0");
        decl->append_attribute(decl_ver);
        doc.append_node(decl);
        xml_node<>* node =
            doc.allocate_node(node_element,    "Hello", "World");
        doc.append_node(node);
        string text;
        rapidxml::print(std::back_inserter(text), doc, 0);
        // write text to file by yourself
    }

下面是使用RapidXML分析XML的样例代码:

view plaincopy to clipboardprint?
void parse_doc_by_rapidxml(char* xml_doc)  
{  
    xml_document<> doc;        // character type defaults to char  
    doc.parse<0>(xml_doc); // 0 means default parse flags  
    xml_node<> *node = doc.first_node("Hello");  
    string node_val = node->value();  
}
    void parse_doc_by_rapidxml(char* xml_doc)
    {
        xml_document<> doc;        // character type defaults to char
        doc.parse<0>(xml_doc); // 0 means default parse flags
        xml_node<> *node = doc.first_node("Hello");
        string node_val = node->value();
    }




首先上一个简单的xml写文件
如下:

#include < iostream >
#include
< rapidxml / rapidxml.hpp >
#include
< rapidxml / rapidxml_utils.hpp >
#include
< rapidxml / rapidxml_print.hpp >

using namespace rapidxml;

int main()
{    
      xml_document
<> doc;  
      xml_node
<>* rot = doc.allocate_node(rapidxml::node_pi,doc.allocate_string( " xml version='1.0' encoding='utf-8' " ));
      doc.append_node(rot);
      xml_node
<>* node =    doc.allocate_node(node_element, " config " , " information " );  
      xml_node
<>* color =    doc.allocate_node(node_element, " color " ,NULL);  
      doc.append_node(node);
      node
-> append_node(color);
      color
-> append_node(doc.allocate_node(node_element, " red " , " 0.1 " ));
      color
-> append_node(doc.allocate_node(node_element, " green " , " 0.1 " ));
      color
-> append_node(doc.allocate_node(node_element, " blue " , " 0.1 " ));
      color
-> append_node(doc.allocate_node(node_element, " alpha " , " 1.0 " ));

      xml_node
<>* size =    doc.allocate_node(node_element, " size " ,NULL);
      size
-> append_node(doc.allocate_node(node_element, " x " , " 640 " ));
      size
-> append_node(doc.allocate_node(node_element, " y " , " 480 " ));
      node
-> append_node(size);

      xml_node
<>* mode = doc.allocate_node(rapidxml::node_element, " mode " , " screen mode " );
      mode
-> append_attribute(doc.allocate_attribute( " fullscreen " , " false " ));
      node
-> append_node(mode);

      std::
string text;  
      rapidxml::print(std::back_inserter(text), doc,
0 );  

      std::cout
<< text << std::endl;
    
      std::ofstream
out ( " config.xml " );
     
out << doc;

      system(
" PAUSE " );
     
return EXIT_SUCCESS;
}

生成的xml文件为:
<? xml version='1.0' encoding='utf-8' ?>
< config >
    
< color >
        
< red > 0.1 </ red >
        
< green > 0.1 </ green >
        
< blue > 0.1 </ blue >
        
< alpha > 1.0 </ alpha >
    
</ color >
    
< size >
        
< x > 640 </ x >
        
< y > 480 </ y >
    
</ size >
    
< mode fullscreen ="false" > screen mode </ mode >
</ config >


说实话 感觉这个比较不错
希望更多的人使用它!


接上篇
本文主要涉及rapidxml读文件的操作

基本的步骤为

首先获取xml文件数据
然后分析数据
获取节点
获取属性
获取名字
获取值
...

代码如下:

#include < iostream >
#include
< rapidxml / rapidxml.hpp >
#include
< rapidxml / rapidxml_utils.hpp >
#include
< rapidxml / rapidxml_print.hpp >

using namespace rapidxml;

int main()
{    
      file
<> fdoc( " config.xml " );
      std::cout
<< fdoc.data() << std::endl;
      xml_document
<>    doc;    
      doc.parse
< 0 > (fdoc.data());

      std::cout
<< doc.name() << std::endl;
     
     
// ! 获取根节点
      xml_node <>* root = doc.first_node();
      std::cout
<< root -> name() << std::endl;

     
// ! 获取根节点第一个节点
      xml_node <>* node1 = root -> first_node();
      std::cout
<< node1 -> name() << std::endl;

      xml_node
<>* node11 = node1 -> first_node();
      std::cout
<< node11 -> name() << std::endl;
      std::cout
<< node11 -> value() << std::endl;
     
     
// ! 修改之后再次保存
      xml_node <>* size = root -> first_node( " size " );
      size
-> append_node(doc.allocate_node(node_element, " w " , " 0 " ));
      size
-> append_node(doc.allocate_node(node_element, " h " , " 0 " ));

      std::
string text;  
      rapidxml::print(std::back_inserter(text),doc,
0 );  

      std::cout
<< text << std::endl;
    
      std::ofstream
out ( " config.xml " );
     
out << doc;

      system(
" PAUSE " );
     
return EXIT_SUCCESS;
}


生成的xml为:

<? xml version='1.0' encoding='utf-8' ?>
< config >
    
< color >
        
< red > 0.1 </ red >
        
< green > 0.1 </ green >
        
< blue > 0.1 </ blue >
        
< alpha > 1.0 </ alpha >
    
</ color >
    
< size >
        
< x > 640 </ x >
        
< y > 480 </ y >
    
</ size >
    
< mode fullscreen ="false" > screen mode </ mode >
</ config >

需要说明的是rapidxml明显有一个bug
那就是append_node(doc.allocate_node(node_element,"h","0"));的时候并不考虑该对象是否存在!

经过这2篇 基本上就可以使用xml了
当然这里并没有涉及异常处理

你可能感兴趣的:(游戏配置之XML)