From c53d79a8cf976a88a80dc3e9b5d9bc9d3d7c8277 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 15 Nov 2025 17:42:02 +0000 Subject: [PATCH] XML Document element traversal Allows traversing an xml document by element without needing to know the element name Blind traversal allows more dynamic loading of xml docs and logic to wrap different outcomes new script functions: prevElement nextElement nextChildElement
<--- we are here <-- nextChildElement will take us here <-- after nextChildElement nextElement will take us here
<-- next element will bring us here --- Engine/source/console/SimXMLDocument.cpp | 95 ++++++++++++++++++++++++ Engine/source/console/SimXMLDocument.h | 6 ++ 2 files changed, 101 insertions(+) diff --git a/Engine/source/console/SimXMLDocument.cpp b/Engine/source/console/SimXMLDocument.cpp index fb8b538c4..b565b1b31 100644 --- a/Engine/source/console/SimXMLDocument.cpp +++ b/Engine/source/console/SimXMLDocument.cpp @@ -1419,4 +1419,99 @@ DefineEngineMethod( SimXMLDocument, getData, const char*, (),, return text; } +bool SimXMLDocument::prevElement() +{ + m_CurrentAttribute = NULL; + + if (m_paNode.empty()) + return false; + + S32 idx = m_paNode.size() - 1; + tinyxml2::XMLNode*& curr = m_paNode[idx]; + + if (!curr) + return false; + + tinyxml2::XMLNode* prev = curr->PreviousSiblingElement(); + + if (!prev) + return false; + + curr = prev; + return true; +} + +DefineEngineMethod(SimXMLDocument, prevElement, const char*, (), , + "@brief Move to previous sibling element regardless of name.\n" + "@return The element name, or empty string if none.\n") +{ + if (object->prevElement()) + return object->elementValue(); + + return ""; +} + +bool SimXMLDocument::nextElement() +{ + m_CurrentAttribute = NULL; + + if (m_paNode.empty()) + return false; + + S32 idx = m_paNode.size() - 1; + tinyxml2::XMLNode*& curr = m_paNode[idx]; + + if (!curr) + return false; + + tinyxml2::XMLNode* next = curr->NextSiblingElement(); + + if (!next) + return false; + + curr = next; + return true; +} + +DefineEngineMethod(SimXMLDocument, nextElement, const char*, (), , + "@brief Move to next sibling element regardless of name.\n" + "@return The element name, or empty string if none.\n") +{ + if (object->nextElement()) + return object->elementValue(); // return the name of the element + + return ""; +} + +bool SimXMLDocument::nextChildElement() +{ + m_CurrentAttribute = NULL; + + if (m_paNode.empty()) + return false; + + tinyxml2::XMLNode* parent = m_paNode.back(); + if (!parent) + return false; + + tinyxml2::XMLElement* firstChild = parent->FirstChildElement(); + if (!firstChild) + return false; + + m_paNode.push_back(firstChild); + return true; +} + +DefineEngineMethod(SimXMLDocument, nextChildElement, const char*, (),, + "@brief Move to the next child element under the same parent.\n" + "@return True if a next child exists, false otherwise.") +{ + if (object->nextChildElement()) + { + const char* name = object->elementValue(); + return name ? name : ""; + } + return ""; +} + ////EOF///////////////////////////////////////////////////////////////////////// diff --git a/Engine/source/console/SimXMLDocument.h b/Engine/source/console/SimXMLDocument.h index 96d63eeb8..c95ee9366 100644 --- a/Engine/source/console/SimXMLDocument.h +++ b/Engine/source/console/SimXMLDocument.h @@ -132,6 +132,12 @@ class SimXMLDocument: public SimObject void addData(const char* text); // Retrieve data from the current level. const char* getData(); + + bool prevElement(); + + bool nextElement(); + + bool nextChildElement(); private: // Document.