UE4+XML文件读取

虚幻引擎: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
发布了40 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/zhangmei126/article/details/103476407
今日推荐