虚幻引擎:4.22
VS:2017
XML文件的读取,对于应用开发,项目配置很是方便。
此帖将XML文件读取集成为UE4的插件,然后写了一个简单的工程,解释了实际项目开发中的使用。
XML文件读取插件,利用了Tinyxml来读取xml文件,给出他的官网地址:http://www.grinninglizard.com/tinyxml/
直接附上XML文件读取插件的Github地址:https://github.com/zhangmei126/XML
接下来讲一下XML文件读取的工程,开发框架:
1、先创建一个空工程命名为XMLTest
2、然后创建继承自GameInstance的类,命名为XMLTestGameInstance
- 目的:当项目设置了自定义的XMLTestGameInstance类,在XMLTestGameInstance初始化的时候,加载项目所有的系统配置(比如分辨率,语言设置,HTTP初始化,OSS服务器初始化,第三方库等等)。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "XMLTestGameInstance.generated.h"
/**
*
*/
UCLASS()
class XMLTEST_API UXMLTestGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
virtual void Init() override;
virtual void Shutdown() override;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestGameInstance.h"
#include "XMLTestPrototypeManager.h"
void UXMLTestGameInstance::Init()
{
Super::Init();
//加载系统所有配置.
XMLTestPrototypeManager::GetInstance()->LoadAllSystemPrototype();
}
void UXMLTestGameInstance::Shutdown()
{
}
3、创建管理XML配置文件的Manager类,命名为XMLTestPrototypeManager
- 目的:项目中会有很多XML配置,Manager类就很关键,它是个全局访问的单利,提供统一的接口,查找到对应的XML表。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include <map>
#include "XMLTestBasePrototype.h"
//通过pid直接获取Prototype对象.
typedef std::map<int32, XMLTestBasePrototype*> XMLTestPrototypeMap;
/**
*
*/
class XMLTEST_API XMLTestPrototypeManager
{
public:
XMLTestPrototypeManager();
virtual ~XMLTestPrototypeManager();
//单利
static XMLTestPrototypeManager * GetInstance();
void LoadAllSystemPrototype();
bool LoadPrototype(const FString & _XmlPath);
XMLTestBasePrototype* GetPrototypeByPID(int32 _Pid);
template<typename T>
T* GetPrototypeByPID(int32 _Pid)
{
std::map<int32, XMLTestBasePrototype*>::iterator it = m_PrototypeMap.find(_Pid);
if (it != m_PrototypeMap.end())
{
XMLTestBasePrototype* mPrototype = it->second;
return (T*)mPrototype;
}
return nullptr;
}
public:
static XMLTestPrototypeManager* m_XMLTestPrototypeManager;
//PrototypeMap字典.
XMLTestPrototypeMap m_PrototypeMap;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestPrototypeManager.h"
#include <string>
#include "XMLTestBasePrototype.h"
#include "XMLTestLanguagePrototype.h"
#include "Runtime/Core/Public/Misc/Paths.h"
#include "Runtime/Core/Public/Misc/FileHelper.h"
//初始化在主线程前.
XMLTestPrototypeManager* XMLTestPrototypeManager::m_XMLTestPrototypeManager = nullptr;
XMLTestPrototypeManager::XMLTestPrototypeManager()
{
}
XMLTestPrototypeManager::~XMLTestPrototypeManager()
{
}
XMLTestPrototypeManager * XMLTestPrototypeManager::GetInstance()
{
//判断是否第一次调用.
if (m_XMLTestPrototypeManager == nullptr)
{
m_XMLTestPrototypeManager = new XMLTestPrototypeManager();
}
return m_XMLTestPrototypeManager;
}
void XMLTestPrototypeManager::LoadAllSystemPrototype()
{
FString mConfigDir = FPaths::ConvertRelativePathToFull(FPaths::ProjectConfigDir());
FString mXmlConfigDir = FString::Printf(TEXT("%s%s"), *mConfigDir, TEXT("XML/"));
LoadPrototype(FString::Printf(TEXT("%s%s"), *mXmlConfigDir, TEXT("ChinesePrototype.xml")));
}
bool XMLTestPrototypeManager::LoadPrototype(const FString & _XmlPath)
{
TiXmlDocument mXmlDocument;
FString mStrContent;
if (!FFileHelper::LoadFileToString(mStrContent, *_XmlPath))
{
return false;
}
FString mContent = mStrContent;
std::string mStdContent = TCHAR_TO_UTF8(*mContent);
const char * mXmlContent = mStdContent.c_str();
mXmlDocument.Parse(mXmlContent);
TiXmlElement* mXmlRoot = mXmlDocument.FirstChildElement();
if (mXmlRoot == NULL)
{
mXmlDocument.Clear();
return false;
}
const char * mXmlNodeType = mXmlRoot->Attribute("type");
for (TiXmlElement* mElem = mXmlRoot->FirstChildElement(); mElem != NULL; mElem = mElem->NextSiblingElement())
{
XMLTestBasePrototype * mPrototype;
const char * mPid = mElem->Attribute("pid");
//根据Pid查找Prototype.
std::map<int32, XMLTestBasePrototype*>::iterator it = m_PrototypeMap.find(atoi(mPid));
if (it != m_PrototypeMap.end())
{
mPrototype = it->second;
mPrototype->LoadXMLData(mElem);
}
else
{
mPrototype = (XMLTestBasePrototype *)(new XMLTestLanguagePrototype());
mPrototype->LoadXMLData(mElem);
m_PrototypeMap.insert(std::make_pair(atoi(mPid), mPrototype));
}
}
mXmlDocument.Clear();
return true;
}
XMLTestBasePrototype* XMLTestPrototypeManager::GetPrototypeByPID(int32 _Pid)
{
std::map<int32, XMLTestBasePrototype*>::iterator it = m_PrototypeMap.find(_Pid);
if (it != m_PrototypeMap.end())
{
XMLTestBasePrototype* mPrototype = it->second;
return mPrototype;
}
return nullptr;
}
4、创建XML配置文件的一个基类,命名为XMLTestBasePrototype
- 目的:各个XML配置文件其实都有相同之处,创建一个基类是很有必要的。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "tinyxml.h"
#include "tinystr.h"
/**
*
*/
class XMLTEST_API XMLTestBasePrototype
{
public:
XMLTestBasePrototype();
virtual ~XMLTestBasePrototype();
virtual void LoadXMLData(TiXmlElement * _XmlElement) final;
protected:
virtual void OnLoadXMLData(TiXmlElement * _XmlElement);
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestBasePrototype.h"
XMLTestBasePrototype::XMLTestBasePrototype()
{
}
XMLTestBasePrototype::~XMLTestBasePrototype()
{
}
void XMLTestBasePrototype::LoadXMLData(TiXmlElement * _XmlElement)
{
OnLoadXMLData(_XmlElement);
}
void XMLTestBasePrototype::OnLoadXMLData(TiXmlElement * _XmlElement)
{
}
4、创建继承自XMLTestBasePrototype的类,命名为XMLTestLanguagePrototype
- 目的:在这个测试XML文件读取的项目中,举了一个例子测试读取语言配置的XML文件,所以创建对应的派生。然后具体的实现将会存储语言配置XML文件中,key和value的对应值,方便接下来的查找。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "XMLTestBasePrototype.h"
/**
*
*/
class XMLTEST_API XMLTestLanguagePrototype : public XMLTestBasePrototype
{
public:
XMLTestLanguagePrototype();
virtual ~XMLTestLanguagePrototype();
protected:
virtual void OnLoadXMLData(TiXmlElement* _XmlElement) override;
public:
FString GetLanguage(const FString& _Key);
FString GetLanguageTexture2D(const FString& _Key);
private:
//文字对应的Key Value;
TMap<FString, FString> m_Values;
//图片对应的Key Value;
TMap<FString, FString> m_AssetValues;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestLanguagePrototype.h"
XMLTestLanguagePrototype::XMLTestLanguagePrototype()
{
}
XMLTestLanguagePrototype::~XMLTestLanguagePrototype()
{
}
void XMLTestLanguagePrototype::OnLoadXMLData(TiXmlElement* _XmlElement)
{
for (TiXmlElement* mXmlElement = _XmlElement->FirstChildElement(); mXmlElement != NULL; mXmlElement = mXmlElement->NextSiblingElement())
{
const char* mKey = mXmlElement->Attribute("key");
const char* mValue = mXmlElement->Attribute("value");
const char* mAssetUrl = mXmlElement->Attribute("asset");
m_Values.Add(UTF8_TO_TCHAR(mKey), UTF8_TO_TCHAR(mValue));
m_AssetValues.Add(UTF8_TO_TCHAR(mKey), UTF8_TO_TCHAR(mAssetUrl));
}
}
FString XMLTestLanguagePrototype::GetLanguage(const FString& _Key)
{
if (m_Values.Contains(_Key))
{
return m_Values[_Key];
}
return TEXT("");
}
FString XMLTestLanguagePrototype::GetLanguageTexture2D(const FString& _Key)
{
if (m_AssetValues.Contains(_Key))
{
return m_AssetValues[_Key];
}
return TEXT("");
}
5、创建读取语言配置XML文件的工具类,命名为XMLTestLanguageTool
- 目的:项目中直接调用XMLTestLanguageTool单利对应的获取语言的方法,而不用管上面其他类的实现。因为上面的类的功能都是在XMLTestGameInstance加载的时候就已经实现了。项目中直接调用的话,就使用一个XMLTestLanguageTool中的单利直接调用,方便而且封装性好。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/**
*
*/
class XMLTEST_API XMLTestLanguageTool
{
public:
XMLTestLanguageTool();
virtual ~XMLTestLanguageTool();
static XMLTestLanguageTool * GetInstance();
FString GetLanguage(const FString & _key);
FString GetLanguageTexture2D(const FString & _key);
private:
// 单利.
static XMLTestLanguageTool * m_LanguageInstance;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestLanguageTool.h"
#include "XMLTestPrototypeManager.h"
#include "XMLTestLanguagePrototype.h"
//初始化在主线程之前.
XMLTestLanguageTool* XMLTestLanguageTool::m_LanguageInstance = nullptr;
XMLTestLanguageTool::XMLTestLanguageTool()
{
}
XMLTestLanguageTool::~XMLTestLanguageTool()
{
}
XMLTestLanguageTool * XMLTestLanguageTool::GetInstance()
{
//判断是否第一次调用.
if (m_LanguageInstance == nullptr)
{
m_LanguageInstance = new XMLTestLanguageTool();
}
return m_LanguageInstance;
}
FString XMLTestLanguageTool::GetLanguage(const FString & _Key)
{
return XMLTestPrototypeManager::GetInstance()->GetPrototypeByPID<XMLTestLanguagePrototype>(100)->GetLanguage(_Key);
}
FString XMLTestLanguageTool::GetLanguageTexture2D(const FString & _Key)
{
return XMLTestPrototypeManager::GetInstance()->GetPrototypeByPID<XMLTestLanguagePrototype>(100)->GetLanguage(_Key);
}
6、创建一个测试Actor类,命名为XMLTestActor
- 直接调用XMLTestLanguageTool类这个单利中的方法,传入XML文件中语言配置对应的key,获取对应的中文配置。
- .h文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "XMLTestActor.generated.h"
UCLASS()
class XMLTEST_API AXMLTestActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AXMLTestActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
- .cpp文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "XMLTestActor.h"
#include "XMLTest.h"
#include "XMLTestLanguageTool.h"
// Sets default values
AXMLTestActor::AXMLTestActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AXMLTestActor::BeginPlay()
{
Super::BeginPlay();
FString mValue = XMLTestLanguageTool::GetInstance()->GetLanguage(TEXT("key100"));
UE_LOG(XMLTestLog, Log, TEXT("%s"), *mValue);
}
// Called every frame
void AXMLTestActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
7、创建一个XML文件,命名为ChinesePrototype.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
中文语言设置!!!
-->
<root type="LanguagePrototype">
<Platform pid="100" name="">
<language key="key100" value="扳机键" asset=""/>
<language key="key101" value="滑动键" asset=""/>
<language key="key102" value="枪头键" asset=""/>
<language key="key103" value="拨动键" asset=""/>
<language key="key104" value="拨动键" asset=""/>
</root>
8、将第7步的XML文件,放到项目Config/XML文件夹下
- 当加载XMLTestGameInstance的时候,会找到项目工程Config/XML目录下的xml文件,读取里面的中文配置
- 源码测试工程同上面的插件地址:https://github.com/zhangmei126/XML