Skip to content

Commit

Permalink
Implement XML root element editing
Browse files Browse the repository at this point in the history
  • Loading branch information
Drombeys committed Sep 29, 2024
1 parent d227392 commit e23931b
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 84 deletions.
242 changes: 158 additions & 84 deletions src/xrCore/XmlParser/AsureXML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,36 @@
#include "AsureXML.h"
#include <magic_enum/magic_enum.hpp>

CXMLOverride::EOverrideMode CXMLOverride::GetOverrideMode(tinyxml2::XMLElement* Element)
{
if (Element->Attribute("override"))
{
xr_string Copy = Element->Attribute("override");
std::transform(Copy.begin(), Copy.end(), Copy.begin(), [](unsigned char c) { return std::tolower(c); });

return magic_enum::enum_cast<EOverrideMode>(Copy).value_or(EOverrideMode::none);
}

return EOverrideMode::none;
}

IC void CXMLOverride::IterateElement(tinyxml2::XMLElement* Start, std::function<void(tinyxml2::XMLElement*, EOverrideMode)> Callback)
{
if (Start == nullptr)
return;

tinyxml2::XMLElement* ModifElement = Start;
while (ModifElement != nullptr)
{
tinyxml2::XMLElement* TestChild = ModifElement->FirstChildElement();
IterateElement(TestChild, Callback);

if (ModifElement->Attribute("override"))
if (TestChild != nullptr)
{
xr_string Copy = ModifElement->Attribute("override");
std::transform(Copy.begin(), Copy.end(), Copy.begin(), [](unsigned char c) { return std::tolower(c); });
IterateElement(TestChild, Callback);
}

EOverrideMode Mode = magic_enum::enum_cast<EOverrideMode>(Copy).value_or(EOverrideMode::none);
EOverrideMode Mode = GetOverrideMode(ModifElement);
if (Mode != EOverrideMode::none)
{
Callback(ModifElement, Mode);
}

Expand Down Expand Up @@ -57,84 +73,121 @@ void CXMLOverride::ApplyNewNode(tinyxml2::XMLNode* Parent, tinyxml2::XMLElement*
}
}

void CXMLOverride::GenerateNewDoc(tinyxml2::XMLDocument& Original, tinyxml2::XMLDocument& Modif)
{
tinyxml2::XMLElement* ModifElement = Modif.FirstChildElement();
xr_vector<tinyxml2::XMLElement*> ParentList;

IterateElement
(
ModifElement,
[&](tinyxml2::XMLElement* ChildElement, EOverrideMode OverrideMode)
{
if (OverrideMode == EOverrideMode::none)
return;

ParentList.clear();

tinyxml2::XMLNode* Parent = ChildElement->Parent();
while (Parent != nullptr)
{
if (Parent->ToElement() != nullptr)
{
// Root element is null
ParentList.insert(ParentList.begin(), Parent->ToElement());
}
Parent = Parent->Parent();
}
ParentList.push_back(ChildElement);

tinyxml2::XMLElement* IterateElement = Original.FirstChildElement(ParentList[0]->Value());
ParentList.erase(ParentList.begin());

tinyxml2::XMLNode* MyParent = nullptr;

for (auto Element : ParentList)
{
xr_string ElValue = Element->Value();
if (ElValue == "string")
{
const char* IDAttrib = Element->Attribute("id");

IterateElement = IterateElement->FirstChildElement();
while (IterateElement != nullptr)
{
xr_string CheckID = IterateElement->Attribute("id");
if (CheckID == IDAttrib)
break;

IterateElement = IterateElement->NextSiblingElement();
}
}
else
{
tinyxml2::XMLElement* TestChild = IterateElement->FirstChildElement(Element->Value());
if (TestChild != nullptr)
{
IterateElement = TestChild;
}
}
}

MyParent = IterateElement->Parent();

if (OverrideMode == EOverrideMode::remove || OverrideMode == EOverrideMode::replace)
{
size_t NodeCount = MyParent->ChildElementCount();
MyParent->DeleteChild(IterateElement);

if (OverrideMode == EOverrideMode::replace)
{
ApplyNewNode(MyParent, ChildElement);
VERIFY(NodeCount == MyParent->ChildElementCount());
}
}
else if (OverrideMode == EOverrideMode::add)
{
ApplyNewNode(MyParent, ChildElement);
}
}
);
void CXMLOverride::GenerateNewDoc(tinyxml2::XMLDocument& Original, tinyxml2::XMLDocument& Modif) {
tinyxml2::XMLElement* ModifElement = Modif.FirstChildElement();
xr_vector<tinyxml2::XMLElement*> ParentList;

// Обработка корневого элемента отдельно
tinyxml2::XMLElement* OriginalRoot = Original.RootElement();
if (ModifElement != nullptr && OriginalRoot != nullptr)
{
EOverrideMode OverrideMode = GetOverrideMode(ModifElement); // Получение режима переопределения для корневого элемента
if (OverrideMode != EOverrideMode::none)
{
if (OverrideMode == EOverrideMode::remove)
{
Original.DeleteChild(OriginalRoot);
}
else if (OverrideMode == EOverrideMode::replace)
{
Original.DeleteChild(OriginalRoot);
tinyxml2::XMLElement* NewRoot = Original.NewElement(ModifElement->Value());
Original.InsertFirstChild(NewRoot);
CopyAttributes(NewRoot, ModifElement);
CopyChildren(NewRoot, ModifElement);
}
else if (OverrideMode == EOverrideMode::add)
{
// Корневой элемент не может быть добавлен в существующий XML, пропускаем
}
}
}

IterateElement
(
ModifElement,
[&](tinyxml2::XMLElement* ChildElement, EOverrideMode OverrideMode)
{
if (OverrideMode == EOverrideMode::none)
return;

ParentList.clear();

tinyxml2::XMLNode* Parent = ChildElement->Parent();
while (Parent != nullptr)
{
if (Parent->ToElement() != nullptr)
{
ParentList.insert(ParentList.begin(), Parent->ToElement());
}
Parent = Parent->Parent();
}
ParentList.push_back(ChildElement);

tinyxml2::XMLElement* IterateElement = Original.FirstChildElement(ParentList[0]->Value());
ParentList.erase(ParentList.begin());

tinyxml2::XMLNode* MyParent = nullptr;

for (auto Element : ParentList)
{
if (IterateElement == nullptr)
break;

xr_string ElValue = Element->Value();
if (ElValue == "string")
{
const char* IDAttrib = Element->Attribute("id");

IterateElement = IterateElement->FirstChildElement();
while (IterateElement != nullptr)
{
xr_string CheckID = IterateElement->Attribute("id");
if (CheckID == IDAttrib)
break;

IterateElement = IterateElement->NextSiblingElement();
}
}
else
{
tinyxml2::XMLElement* TestChild = IterateElement->FirstChildElement(Element->Value());
if (TestChild != nullptr)
{
IterateElement = TestChild;
}
else
{
IterateElement = nullptr;
}
}
}

if (IterateElement != nullptr)
{
MyParent = IterateElement->Parent();
}

if (MyParent != nullptr)
{
if (OverrideMode == EOverrideMode::remove || OverrideMode == EOverrideMode::replace)
{
size_t NodeCount = MyParent->ChildElementCount();
MyParent->DeleteChild(IterateElement);

if (OverrideMode == EOverrideMode::replace)
{
ApplyNewNode(MyParent, ChildElement);
VERIFY(NodeCount == MyParent->ChildElementCount());
}
}
else if (OverrideMode == EOverrideMode::add)
{
ApplyNewNode(MyParent, ChildElement);
}
}
}
);
}

FS_FileSet CXMLOverride::GetModifFiles(const char* Path, const char* File)
Expand All @@ -154,3 +207,24 @@ FS_FileSet CXMLOverride::GetModifFiles(const char* Path, const char* File)

return std::move(ModifyList);
}

void CXMLOverride::CopyAttributes(tinyxml2::XMLElement* Dest, tinyxml2::XMLElement* Src)
{
const tinyxml2::XMLAttribute* attr = Src->FirstAttribute();
while (attr != nullptr)
{
Dest->SetAttribute(attr->Name(), attr->Value());
attr = attr->Next();
}
}

void CXMLOverride::CopyChildren(tinyxml2::XMLElement* Dest, tinyxml2::XMLElement* Src)
{
for (tinyxml2::XMLElement* child = Src->FirstChildElement(); child != nullptr; child = child->NextSiblingElement())
{
tinyxml2::XMLElement* newChild = Dest->GetDocument()->NewElement(child->Value());
Dest->InsertEndChild(newChild);
CopyAttributes(newChild, child);
CopyChildren(newChild, child);
}
}
3 changes: 3 additions & 0 deletions src/xrCore/XmlParser/AsureXML.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ class CXMLOverride
private:
void IterateElement(tinyxml2::XMLElement* Start, std::function<void(tinyxml2::XMLElement*, EOverrideMode)> Callback);
void ApplyNewNode(tinyxml2::XMLNode* Parent, tinyxml2::XMLElement* Inner);
void CopyAttributes(tinyxml2::XMLElement* Dest, tinyxml2::XMLElement* Src);
void CopyChildren(tinyxml2::XMLElement* Dest, tinyxml2::XMLElement* Src);
EOverrideMode GetOverrideMode(tinyxml2::XMLElement* Element);
};

0 comments on commit e23931b

Please sign in to comment.