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
<think>好的,我现在需要帮助用户在Unreal Engine蓝图中实现XML文件读取解析。根据用户提供的引用资料,我需要先整理已有的信息,然后一步步指导用户操作。 首先,用户提到的引用[4]指出,UE4提供了平台无关的文件读写接口,支持XML文件的处理。这说明UE本身有内置的功能,不需要额外插件。不过引用[3]和[5]提到使用XmlParser库和FXmlFile类,这可能是引擎内置的模块。用户可能需要在项目中启用XmlParser模块,这一步可能需要修改项目的.Build.cs文件,添加“XmlParser”到PublicDependencyModuleNames中。我需要确认这一点是否正确。 接下来,用户需要在蓝图中添加一个ReadXML功能块到BP_PlayerController,并绑定按键O来触发读取并打印IP。根据引用[5]的C++示例,可能需要创建一个蓝图函数库或者使用现有的节点来读取XML。但用户想用蓝图实现,可能需要使用蓝图函数或调用引擎节点。但根据引用[3],用户使用了Unreal的XmlParser库,并通过蓝图Structure定义结构体。这可能涉及到将解析后的数据填充到结构体中,方便蓝图使用。 步骤可能包括:1. 准备XML文件,放置在Content目录下,比如Content/Data/config.xml。2. 在蓝图中使用“Load File to String”节点加载XML文件内容。3. 解析XML内容,这里可能需要调用FXmlFile的相关函数。但蓝图中是否有现成的节点呢?如果没有,可能需要通过C++创建一个蓝图可调用的函数,如引用[5]中的ReadXmlFile,然后在蓝图中调用它。不过用户希望完全在蓝图中完成,可能需要检查是否有插件或内置节点可用。 引用[2]提到有一个市场插件可以处理XML读写,如果用户不想写代码,可能需要推荐该插件。但用户的问题是关于使用蓝图,所以需要说明两种方法:使用内置功能(可能需要C++辅助)或者使用插件。 综上,步骤应该是:首先确保XmlParser模块已启用,然后通过蓝图加载文件内容,接着解析XML。但蓝图中可能没有直接解析XML的节点,所以需要创建自定义函数或在C++中处理,再暴露给蓝图。或者使用插件简化流程。需要分情况说明,并引用相关的引用资料作为支持。</think>### 分步实现UE蓝图解析XML文件 #### 步骤1:准备XML文件XML文件(如`config.xml`)放置在项目`Content/Data`目录下,格式示例: ```xml <ServerConfig> <IP>192.168.1.100</IP> <Port>8080</Port> </ServerConfig> ``` #### 步骤2:启用XmlParser模块(关键配置) 1. 打开项目根目录的`YourProjectName.Build.cs`文件 2. 添加模块依赖项: ```csharp PublicDependencyModuleNames.AddRange(new string[] { "Core", "XmlParser" // 添加引擎内置XML解析模块 }); ``` #### 步骤3:创建蓝图可调用函数(C++层) 创建继承自`BlueprintFunctionLibrary`的C++类(如`XmlHelper`),暴露解析方法: ```cpp // XmlHelper.h UFUNCTION(BlueprintCallable, Category="XML") static FString GetXmlValue(const FString& FilePath, const FString& Tag); ``` ```cpp // XmlHelper.cpp FString UXmlHelper::GetXmlValue(const FString& Path, const FString& Tag) { TSharedPtr<FXmlFile> XmlFile = MakeShareable(new FXmlFile(Path)); if(!XmlFile->IsValid()) return ""; FXmlNode* Root = XmlFile->GetRootNode(); for(FXmlNode* Node : Root->GetChildrenNodes()) { if(Node->GetTag() == Tag) return Node->GetContent(); } return ""; } ``` #### 步骤4:蓝图实现流程 1. **创建键盘事件绑定** - 在`BP_PlayerController`的事件图表中: ```python O键被按下时 -> 执行XML读取逻辑 ``` 2. **加载并解析XML** ![蓝图节点示意图](https://via.placeholder.com/600x200?text=Load+File+to+String+->+GetXmlValue+节点) 3. **打印结果** ```python Print String节点:显示"服务器IP: "+解析结果 ``` #### 两种实现方案对比 | 方案 | 优点 | 缺点 | 适用场景 | |------|------|------|----------| | 内置XmlParser | 无需额外插件 | 需要C++代码支持 | 需要深度定制解析逻辑 | | 市场插件[^2] | 纯蓝图实现 | 需付费购买 | 快速实现基础功能 | #### 高级技巧 1. **结构体映射**:将XML数据映射到蓝图结构体,实现类型安全访问[^3] 2. **错误处理**:添加`isValid`检查,防止空节点崩溃 3. **异步加载**:使用AsyncTask避免主线程卡顿
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值