Pugi xml usablity



In previous posting we've checked how to download and setup pugixml enviroment.


Okay, We are ready to use pugixml.  

To use a pugixml I usually create singleton class which managing all input/output of XML stream. here my case is just reference. There will be bundle of different way to use pugixml with more efficiency.



Here is a basic code to use pugixml.


//----------------------------------------------------------------- Pugixml API

#include "pugixml.hpp"


//------------------------------------------------------------------------ Json

#include "json\document.h"

#include "json\writer.h"

#include "json\reader.h"

#include "json\prettywriter.h"

#include "json\stringbuffer.h"


//-----------------------------------------------------------Cocos2d Name space

USING_NS_CC;

using namespace rapidjson;



include header file as like upper box

then implement code like below.

(this code is load local xml file and get data)


void MainScene::getPugixmlSample()

{

pugi::xml_document _xmlDoc;

pugi::xml_node _xmlNode;


std::string path = CCFileUtils::sharedFileUtils()->getWritablePath();

path.append("data.xml");


if (!FileUtils::sharedFileUtils()->isFileExist(path))

{

auto data = FileUtils::getInstance()->getDataFromFile("data/data.xml");

std::string dbPath = FileUtils::getInstance()->getWritablePath() + "data.xml";


FILE* dest = fopen(dbPath.c_str(), "wb");

fwrite(data.getBytes(), 1, data.getSize(), dest);

fclose(dest);

}


unsigned char* pBuffer = NULL;

ssize_t bufferSize = 0;

pBuffer = CCFileUtils::sharedFileUtils()->getFileData(path.c_str(), "r", &bufferSize);

if (_xmlDoc.load_buffer(pBuffer, bufferSize))

_xmlNode = _xmlDoc.child("root");


  // read data from xml file

pugi::xml_node stage = _xmlNode.child("stage");

        int world = stage.attribute("world").as_int();

int slot = stage.attribute("slot").as_int();

}



oh. I forget to show local xml file. XML file structure is like this.



<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<root>

<stage world="0" slot="0"/>

</root>




Here is attached singleton class what i used for development. Once you have this kind of singleton class, will be reduce develop time in another project. 


here code is header file named as "XmlMngt.h"


#ifndef __XmlMngt_H__

#define __XmlMngt_H__


//--------------------------------------------------------------Cocos2d Include

#include "cocos2d.h"


//----------------------------------------------------------------- Pugixml API

#include "pugixml.hpp"


//------------------------------------------------------------------------ Json

#include "json\document.h"

#include "json\writer.h"

#include "json\reader.h"

#include "json\prettywriter.h"

#include "json\stringbuffer.h"


//-----------------------------------------------------------Cocos2d Name space

USING_NS_CC;

using namespace rapidjson;


//-----------------------------------------------------------------------------

class XmlMngt

{

public:

XmlMngt();

~XmlMngt();


// Singleton object

static XmlMngt& getInstance();

static void releaseInstance();

static XmlMngt* m_pInstance;


void loadXml();


int getHighScore();

  void setHighScore(const int &iScore);


void saveXml();


private:

pugi::xml_document _xmlDoc;

pugi::xml_node _xmlNode;

};


#endif




here code is cpp file named as "XmlMngt.cpp"


#pragma execution_character_set("utf-8")



#include "XmlMngt.h"


XmlMngt *XmlMngt::m_pInstance = nullptr;


XmlMngt::XmlMngt()

{

loadXml();

}


XmlMngt::~XmlMngt() {}


XmlMngt& XmlMngt::getInstance()

{

if (m_pInstance == nullptr)

m_pInstance = new XmlMngt();


return *m_pInstance;

}


void XmlMngt::releaseInstance()

{

if (m_pInstance != nullptr)

delete m_pInstance;

}



void XmlMngt::loadXml()

{

std::string path = CCFileUtils::sharedFileUtils()->getWritablePath();

path.append("data.xml");


if (!FileUtils::sharedFileUtils()->isFileExist(path))

{

auto data = FileUtils::getInstance()->getDataFromFile("data/data.xml");

std::string dbPath = FileUtils::getInstance()->getWritablePath() + "data.xml";


FILE* dest = fopen(dbPath.c_str(), "wb");

fwrite(data.getBytes(), 1, data.getSize(), dest);

fclose(dest);

}


unsigned char* pBuffer = NULL;

ssize_t bufferSize = 0;

pBuffer = CCFileUtils::sharedFileUtils()->getFileData(path.c_str(), "r", &bufferSize);

if (_xmlDoc.load_buffer(pBuffer, bufferSize))

_xmlNode = _xmlDoc.child("root");

}


void XmlMngt::saveXml()

{

std::string configPath = CCFileUtils::sharedFileUtils()->getWritablePath();

configPath.append("data.xml");

_xmlDoc.save_file(configPath.c_str());

}


int XmlMngt::getHighScore(const int &iScore)

{

pugi::xml_node highscore = _xmlNode.child("highscore");

_gHighScore = highscore.attribute("score").as_llong();

if (iScore > _gHighScore)

{

_gHighScore = iScore;

highscore.attribute("score").set_value(_gHighScore);

saveXml();

}

}


void XmlMngt::setHighScore(const int &iScore)

{

pugi::xml_node highscore = _xmlNode.child("highscore");

_gHighScore = highscore.attribute("score").as_int();

if (iScore > _gHighScore)

{

_gHighScore = iScore;

highscore.attribute("score").set_value(_gHighScore);

saveXml();

}

}



last point is that, where wil be copied this local xml file.

Especilly in Cocos2d enviroment(in Windows) , xml file copied under "c:/user/AppData/Local/[Your Project Name]


By default, AppData folder is hidden. you need to check show option first.