Skip to content

IO: add support for reading/writing XML attributes #267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/IO/configuration_JSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
59 changes: 50 additions & 9 deletions src/IO/configuration_XML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const char*>(nodeContent));
config->set(key, value);
option.value = reinterpret_cast<const char*>(nodeContent);
xmlFree(nodeContent);

xmlAttr *attribute = node->properties;
while (attribute) {
xmlChar* attributeValue = xmlNodeListGetString(node->doc, attribute->children, 1);
option.attributes[reinterpret_cast<const char*>(attribute->name)] = reinterpret_cast<const char*>(attributeValue);
xmlFree(attributeValue);

attribute = attribute->next;
}

config->addOption(key, std::move(option));
}
}
}
Expand All @@ -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");
}
}

Expand Down
210 changes: 197 additions & 13 deletions src/IO/configuration_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Option &>(static_cast<const Config &>(*this).getOption(key));
}

/*!
Gets a constant reference to the specified option.

\param key is the name of the option
\result A constant reference to the specified option.
*/
const Config::Option & Config::getOption(const std::string &key) const
{
return (*m_options).at(key);
}

/*!
Gets the specified option.
Gets the value of the specified option.

If the option does not exists an exception is thrown.

\param key is the name of the option
\result The specified option.
\result The value of the specified option.
*/
const std::string & Config::get(const std::string &key) const
{
return m_options->at(key);
return getOption(key).value;
}

/*!
Gets the specified option.
Gets the value of the specified option.

If the option does not exists the fallback value is returned.

\param key is the name of the option
\param fallback is the value that will be returned if the specified
options does not exist
\result The specified option or the fallback value if the specified
\result The value of the specified option or the fallback value if the
options does not exist.
*/
std::string Config::get(const std::string &key, const std::string &fallback) const
{
if (hasOption(key)) {
return get(key);
return getOption(key).value;
} else {
return fallback;
}
}

/*!
Set the given option to the specified value
Set the value of the specified option.

If the option does not exists, a new option will be added.

\param key is the name of the option
\param value is the value of the option
*/
void Config::set(const std::string &key, const std::string &value)
{
(*m_options)[key] = value;
if (hasOption(key)) {
getOption(key).value = value;
} else {
addOption(key, value);
}
}

/*!
Gets the value of the specified option attribute.

If the option or the attribute does not exists, an exception is thrown.

\param key is the name of the option
\param name is the name of the attribute
\result The value of the specified attribute.
*/
const std::string & Config::getAttribute(const std::string &key, const std::string &name) const
{
return getOption(key).attributes.at(name);
}

/*!
Gets the value of the specified option attribute.

If the option does not exists, an exception will be thrown. However, if
the attribute do not exists, the fallback walue will be returned

\param key is the name of the option
\param name is the name of the attribute
\param fallback is the value that will be returned if the specified
attribute does not exist
\result The value of the specified attribute or the fallback value if
the options or the attribute does not exist.
*/
std::string Config::getAttribute(const std::string &key, const std::string &name, const std::string &fallback) const
{
const Option &option = getOption(key);
if (option.attributes.count(name) > 0) {
return option.attributes.at(name);
}

return fallback;
}

/*!
Set the value of the specified option attribute.

If the option does not exists, an exception will be thrown. However,
if the attribute does not exists, a new attribute will be added.

\param key is the name of the option
\param name is the name of the attribute
\param value is the value of the attribute
*/
void Config::setAttribute(const std::string &key, const std::string &name, const std::string &value)
{
getOption(key).attributes[name] = value;
}

/*!
Checks if the specified option exists.

\param key is the name of the option
\result True is the option exists, false otherwise.
*/
bool Config::hasOption(const std::string &key) const
{
return (m_options->count(key) > 0);
}

/*!
Add an option to the configuration storage.

If an option with the same key already exists, it will be overwritten.

\param key is the name of the option
\param option is the option that will be added
*/
void Config::addOption(const std::string &key, const Option &option)
{
(*m_options)[key] = option;
}

/*!
Add an option to the configuration storage.

If an option with the same key already exists, it will be overwritten.

\param key is the name of the option
\param option is the option that will be added
*/
void Config::addOption(const std::string &key, Option &&option)
{
(*m_options)[key] = std::move(option);
}

/*!
Add an option to the configuration storage.

If an option with the same key already exists, it will be overwritten.

\param key is the name of the option
\param value is the value of the option
*/
void Config::addOption(const std::string &key, const std::string &value)
{
addOption(key, std::string(value), Attributes());
}

/*!
Add an option to the configuration storage.

If an option with the same key already exists, it will be overwritten.

\param key is the name of the option
\param value is the value of the option
*/
void Config::addOption(const std::string &key, std::string &&value)
{
addOption(key, std::move(value), Attributes());
}

/*!
Add an option to the configuration storage.

If an option with the same key already exists, it will be overwritten.

\param key is the name of the option
\param value is the value of the option
\param attributes are the attributes of the option
*/
void Config::addOption(const std::string &key, const std::string &value, const Attributes &attributes)
{
Option option;
option.value = value;
option.attributes = attributes;

addOption(key, std::move(option));
}

/*!
Add an option to the configuration storage.

If an option with the same key already exists, it will be overwritten.

\param key is the name of the option
\param value is the value of the option
\param attributes are the attributes of the option
*/
void Config::addOption(const std::string &key, std::string &&value, Attributes &&attributes)
{
Option option;
option.value = std::move(value);
option.attributes = std::move(attributes);

addOption(key, std::move(option));
}

/*!
Expand Down Expand Up @@ -402,7 +570,23 @@ void Config::dump(std::ostream &out, int indentLevel) const
out << indent << "Options..." << std::endl;
if (getOptionCount() > 0) {
for (const auto &entry : getOptions()) {
out << indent << padding << entry.first << " = " << entry.second << std::endl;
const std::string &key = entry.first;
const Option &option = entry.second;

// Option value
out << indent << padding << key << " = " << option.value << std::endl;

// Option attributes
if (!option.attributes.empty()) {
for (const auto &attributeEntry : option.attributes) {
const std::string &name = attributeEntry.first;
const std::string &value = attributeEntry.second;

out << indent << padding << padding << "Attribute: " << name << " = " << value << std::endl;
}
} else {
out << indent << padding << padding << "Option has not attributes." << std::endl;
}
}
} else {
out << indent << padding << "No options." << std::endl;
Expand Down
Loading