#include "ntxnodexml.h" #include #include #include #include // 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; if constexpr (std::is_same_v) { // Überspringe leere Werte } else if constexpr (std::is_same_v) { childElement.append_attribute(key.c_str()).set_value(arg.c_str()); } else if constexpr (std::is_same_v) { childElement.append_attribute(key.c_str()).set_value(arg); } else if constexpr (std::is_same_v) { childElement.append_attribute(key.c_str()).set_value(arg); } else if constexpr (std::is_same_v) { 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(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(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