added nodes.

This commit is contained in:
Christoph Holzheuer
2026-04-02 15:15:28 +02:00
parent b05180f575
commit 0b54793b08
43 changed files with 4371 additions and 0 deletions

View File

@@ -0,0 +1,209 @@
#include "ntxnodexml.h"
#include <ntxnodefactory.h>
#include <pugixml.hpp>
#include <iostream>
#include <sstream> // Add this include at the top of the file
namespace ntx
{
// Rekursive Hilfsfunktion
static NtxNodePtr parseElementRecursive(const pugi::xml_node& xmlNode)
{
if (!xmlNode)
return nullptr;
// 1. Tag-Name als ID-String verwenden
NtxString tagName = xmlNode.name();
// Ignoriere spezielle Knotentypen (Kommentare, PCDATA/Text, etc.) wenn sie leer sind
// In diesem einfachen Beispiel behandeln wir nur Element-Knoten als echte NtxNodes.
if (xmlNode.type() != pugi::node_element)
return nullptr;
// 2. Erzeuge Knoten via Factory (nutzt implizit CTypeFactory für Mapping)
NtxNodePtr newNode = NtxNodeFactory::makeNode(tagName);
if (!newNode)
return nullptr;
// 3. Attribute übertragen
for (pugi::xml_attribute attr : xmlNode.attributes())
{
NtxString key = attr.name();
// Einfache Heuristik für Typen:
// PugiXML liefert strings. Wir könnten versuchen zu konvertieren oder alles als String lassen.
// Hier: Alles als String speichern, oder versuchen int/double zu parsen.
// Fürs erste: Speichern als String, Payload erlaubt mixed types.
newNode->set(key, NtxString(attr.value()));
/* Optional: Intelligentes Parsen
if (attr.as_int() != 0 || std::string(attr.value()) == "0")
newNode->set(key, attr.as_int());
else
newNode->set(key, NtxString(attr.value()));
*/
}
// 4. Kinder rekursiv verarbeiten
for (pugi::xml_node child : xmlNode.children())
{
NtxNodePtr childNode = parseElementRecursive(child);
if (childNode)
{
newNode->addChild(childNode);
}
}
return newNode;
}
NtxNodePtr NtxNodeXml::loadFromFile(const std::string& filename)
{
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(filename.c_str());
if (!result)
{
std::cerr << "XML Load Error: " << result.description() << " in " << filename << std::endl;
return nullptr;
}
// Wir nehmen den ersten Root-Knoten (das Wurzelelement)
// doc.document_element() gibt das erste Kind vom Typ Element zurück (ignoriert PI, DOCTYPE etc.)
return parseElementRecursive(doc.document_element());
}
NtxNodePtr NtxNodeXml::loadFromString(const std::string& xmlContent)
{
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_string(xmlContent.c_str());
if (!result)
{
std::cerr << "XML Parse Error: " << result.description() << std::endl;
return nullptr;
}
return parseElementRecursive(doc.document_element());
}
// Rekursive Hilfsfunktion zum Serialisieren
static void serializeNodeRecursive(const NtxNodeCPtr& node, pugi::xml_node& xmlNode)
{
if (!node)
return;
// 1. Tag-Name aus CType-Label holen
NtxString tagName = node->getClassTypeLabel();
pugi::xml_node childElement = xmlNode.append_child(tagName.c_str());
// 2. Alle Attribute aus dem Payload schreiben
node->forEachProperty([&childElement](const NtxString& key, const NtxVariant& value)
{
// Konvertiere NtxVariant zu String und setze als XML-Attribut
std::visit([&childElement, &key](auto&& arg)
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, std::monostate>)
{
// Überspringe leere Werte
}
else if constexpr (std::is_same_v<T, NtxString>)
{
childElement.append_attribute(key.c_str()).set_value(arg.c_str());
}
else if constexpr (std::is_same_v<T, int>)
{
childElement.append_attribute(key.c_str()).set_value(arg);
}
else if constexpr (std::is_same_v<T, double>)
{
childElement.append_attribute(key.c_str()).set_value(arg);
}
else if constexpr (std::is_same_v<T, bool>)
{
childElement.append_attribute(key.c_str()).set_value(arg);
}
}, value);
});
// 3. Kinder rekursiv verarbeiten
for (size_t i = 0; i < node->getChildCount(); ++i)
{
NtxNodeCPtr child = node->getChild(i);
if (child)
{
serializeNodeRecursive(child, childElement);
}
}
}
bool NtxNodeXml::saveToFile(const NtxNodePtr& node, const std::string& filename)
{
return saveToFile(std::const_pointer_cast<const NtxINode>(node), filename);
}
bool NtxNodeXml::saveToFile(const NtxNodeCPtr& node, const std::string& filename)
{
if (!node)
{
std::cerr << "Cannot save null node to file: " << filename << std::endl;
return false;
}
pugi::xml_document doc;
// XML-Deklaration hinzufügen
pugi::xml_node declaration = doc.prepend_child(pugi::node_declaration);
declaration.append_attribute("version") = "1.0";
declaration.append_attribute("encoding") = "UTF-8";
// Root-Node serialisieren
serializeNodeRecursive(node, doc);
// In Datei speichern mit Formatierung
bool success = doc.save_file(filename.c_str(), " ", pugi::format_default, pugi::encoding_utf8);
if (!success)
{
std::cerr << "Failed to save XML to file: " << filename << std::endl;
}
return success;
}
std::string NtxNodeXml::saveToString(const NtxNodePtr& node)
{
return saveToString(std::const_pointer_cast<const NtxINode>(node));
}
std::string NtxNodeXml::saveToString(const NtxNodeCPtr& node)
{
if (!node)
{
std::cerr << "Cannot serialize null node to string" << std::endl;
return "";
}
pugi::xml_document doc;
// XML-Deklaration hinzufügen
pugi::xml_node declaration = doc.prepend_child(pugi::node_declaration);
declaration.append_attribute("version") = "1.0";
declaration.append_attribute("encoding") = "UTF-8";
// Root-Node serialisieren
serializeNodeRecursive(node, doc);
// In String konvertieren
std::ostringstream oss;
doc.save(oss, " ", pugi::format_default, pugi::encoding_utf8);
return oss.str();
}
} // namespace ntx