From 6c6752e23b4fec21ddc388255ddad0056e4a8059 Mon Sep 17 00:00:00 2001 From: Andrea Iob Date: Tue, 8 Feb 2022 14:11:48 +0100 Subject: [PATCH 1/2] IO/config: add support for reading/writing XML attributes --- src/IO/configuration_JSON.cpp | 8 +- src/IO/configuration_XML.cpp | 59 ++++- src/IO/configuration_config.cpp | 210 ++++++++++++++++-- src/IO/configuration_config.hpp | 39 +++- src/IO/configuration_config.tpp | 69 +++++- .../IO/data/configuration.xml | 10 +- test/integration_tests/IO/test_IO_00004.cpp | 20 +- 7 files changed, 373 insertions(+), 42 deletions(-) diff --git a/src/IO/configuration_JSON.cpp b/src/IO/configuration_JSON.cpp index 50e34ad4d8..12625d9aca 100644 --- a/src/IO/configuration_JSON.cpp +++ b/src/IO/configuration_JSON.cpp @@ -264,13 +264,13 @@ void writeNode(const Config *config, rapidjson::Value &rootJSONData, rapidjson:: { // Write the options for (const auto &entry : config->getOptions()) { - const std::string &configKey = entry.first; - const std::string &configValue = entry.second; + const std::string &key = entry.first; + const Config::Option &option = entry.second; rapidjson::Value jsonKey; - jsonKey.SetString(configKey, allocator); + jsonKey.SetString(key, allocator); - rapidjson::Value jsonValue = encodeValue(configValue, allocator); + rapidjson::Value jsonValue = encodeValue(option.value, allocator); rootJSONData.AddMember(jsonKey, jsonValue, allocator); } diff --git a/src/IO/configuration_XML.cpp b/src/IO/configuration_XML.cpp index a709292e69..4d35d0a2dd 100644 --- a/src/IO/configuration_XML.cpp +++ b/src/IO/configuration_XML.cpp @@ -66,10 +66,22 @@ void readNode(xmlNodePtr root, Config *config) } readNode(node->children, section); } else { + Config::Option option; + xmlChar *nodeContent = xmlNodeGetContent(node); - std::string value(reinterpret_cast(nodeContent)); - config->set(key, value); + option.value = reinterpret_cast(nodeContent); xmlFree(nodeContent); + + xmlAttr *attribute = node->properties; + while (attribute) { + xmlChar* attributeValue = xmlNodeListGetString(node->doc, attribute->children, 1); + option.attributes[reinterpret_cast(attribute->name)] = reinterpret_cast(attributeValue); + xmlFree(attributeValue); + + attribute = attribute->next; + } + + config->addOption(key, std::move(option)); } } } @@ -87,20 +99,49 @@ void writeNode(xmlTextWriterPtr writer, const Config *config, const std::string // Write the options for (const auto &entry : config->getOptions()) { - const std::string &key = entry.first; - const std::string &value = entry.second; + const std::string &key = entry.first; + const Config::Option &option = entry.second; + // Start option xmlChar *elementName = encodeString(key, encoding); - xmlChar *elementText = encodeString(value, encoding); - int status = xmlTextWriterWriteFormatElement(writer, BAD_CAST elementName, "%s", elementText); + status = xmlTextWriterStartElement(writer, BAD_CAST elementName); + if (elementName) { + xmlFree(elementName); + } + if (status < 0) { + throw std::runtime_error("Error at xmlTextWriterStartElement"); + } + + // Write option attributes + for (const auto &attributeEntry : option.attributes) { + xmlChar *attributeName = encodeString(attributeEntry.first, encoding); + xmlChar *attributeValue = encodeString(attributeEntry.second, encoding); + status = xmlTextWriterWriteAttribute(writer, BAD_CAST attributeName, BAD_CAST attributeValue); + if (attributeValue) { + xmlFree(attributeValue); + } + if (attributeName) { + xmlFree(attributeName); + } + if (status < 0) { + throw std::runtime_error("Error at xmlTextWriterWriteAttribute"); + } + } + + // Write option value + xmlChar *elementText = encodeString(option.value, encoding); + status = xmlTextWriterWriteFormatString(writer, "%s", BAD_CAST elementText); if (elementText) { xmlFree(elementText); } - if (elementName) { - xmlFree(elementName); + if (status < 0) { + throw std::runtime_error("Error at xmlTextWriterStartElement"); } + + // End option + status = xmlTextWriterEndElement(writer); if (status < 0) { - throw std::runtime_error("Error at xmlTextWriterWriteFormatElement"); + throw std::runtime_error("Error at xmlTextWriterEndElement"); } } diff --git a/src/IO/configuration_config.cpp b/src/IO/configuration_config.cpp index 44a6cf3683..a9fd834b85 100644 --- a/src/IO/configuration_config.cpp +++ b/src/IO/configuration_config.cpp @@ -133,58 +133,226 @@ const Config::Options & Config::getOptions() const } /*! - Checks if the specified option exists. + Gets a reference to the specified option. \param key is the name of the option - \result True is the option exists, false otherwise. + \result A reference to the specified option. */ -bool Config::hasOption(const std::string &key) const +Config::Option & Config::getOption(const std::string &key) { - return (m_options->count(key) > 0); + return const_cast