Skip to content

Commit 6c6752e

Browse files
committed
IO/config: add support for reading/writing XML attributes
1 parent c868315 commit 6c6752e

File tree

7 files changed

+373
-42
lines changed

7 files changed

+373
-42
lines changed

src/IO/configuration_JSON.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,13 +264,13 @@ void writeNode(const Config *config, rapidjson::Value &rootJSONData, rapidjson::
264264
{
265265
// Write the options
266266
for (const auto &entry : config->getOptions()) {
267-
const std::string &configKey = entry.first;
268-
const std::string &configValue = entry.second;
267+
const std::string &key = entry.first;
268+
const Config::Option &option = entry.second;
269269

270270
rapidjson::Value jsonKey;
271-
jsonKey.SetString(configKey, allocator);
271+
jsonKey.SetString(key, allocator);
272272

273-
rapidjson::Value jsonValue = encodeValue(configValue, allocator);
273+
rapidjson::Value jsonValue = encodeValue(option.value, allocator);
274274

275275
rootJSONData.AddMember(jsonKey, jsonValue, allocator);
276276
}

src/IO/configuration_XML.cpp

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,22 @@ void readNode(xmlNodePtr root, Config *config)
6666
}
6767
readNode(node->children, section);
6868
} else {
69+
Config::Option option;
70+
6971
xmlChar *nodeContent = xmlNodeGetContent(node);
70-
std::string value(reinterpret_cast<const char*>(nodeContent));
71-
config->set(key, value);
72+
option.value = reinterpret_cast<const char*>(nodeContent);
7273
xmlFree(nodeContent);
74+
75+
xmlAttr *attribute = node->properties;
76+
while (attribute) {
77+
xmlChar* attributeValue = xmlNodeListGetString(node->doc, attribute->children, 1);
78+
option.attributes[reinterpret_cast<const char*>(attribute->name)] = reinterpret_cast<const char*>(attributeValue);
79+
xmlFree(attributeValue);
80+
81+
attribute = attribute->next;
82+
}
83+
84+
config->addOption(key, std::move(option));
7385
}
7486
}
7587
}
@@ -87,20 +99,49 @@ void writeNode(xmlTextWriterPtr writer, const Config *config, const std::string
8799

88100
// Write the options
89101
for (const auto &entry : config->getOptions()) {
90-
const std::string &key = entry.first;
91-
const std::string &value = entry.second;
102+
const std::string &key = entry.first;
103+
const Config::Option &option = entry.second;
92104

105+
// Start option
93106
xmlChar *elementName = encodeString(key, encoding);
94-
xmlChar *elementText = encodeString(value, encoding);
95-
int status = xmlTextWriterWriteFormatElement(writer, BAD_CAST elementName, "%s", elementText);
107+
status = xmlTextWriterStartElement(writer, BAD_CAST elementName);
108+
if (elementName) {
109+
xmlFree(elementName);
110+
}
111+
if (status < 0) {
112+
throw std::runtime_error("Error at xmlTextWriterStartElement");
113+
}
114+
115+
// Write option attributes
116+
for (const auto &attributeEntry : option.attributes) {
117+
xmlChar *attributeName = encodeString(attributeEntry.first, encoding);
118+
xmlChar *attributeValue = encodeString(attributeEntry.second, encoding);
119+
status = xmlTextWriterWriteAttribute(writer, BAD_CAST attributeName, BAD_CAST attributeValue);
120+
if (attributeValue) {
121+
xmlFree(attributeValue);
122+
}
123+
if (attributeName) {
124+
xmlFree(attributeName);
125+
}
126+
if (status < 0) {
127+
throw std::runtime_error("Error at xmlTextWriterWriteAttribute");
128+
}
129+
}
130+
131+
// Write option value
132+
xmlChar *elementText = encodeString(option.value, encoding);
133+
status = xmlTextWriterWriteFormatString(writer, "%s", BAD_CAST elementText);
96134
if (elementText) {
97135
xmlFree(elementText);
98136
}
99-
if (elementName) {
100-
xmlFree(elementName);
137+
if (status < 0) {
138+
throw std::runtime_error("Error at xmlTextWriterStartElement");
101139
}
140+
141+
// End option
142+
status = xmlTextWriterEndElement(writer);
102143
if (status < 0) {
103-
throw std::runtime_error("Error at xmlTextWriterWriteFormatElement");
144+
throw std::runtime_error("Error at xmlTextWriterEndElement");
104145
}
105146
}
106147

src/IO/configuration_config.cpp

Lines changed: 197 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -133,58 +133,226 @@ const Config::Options & Config::getOptions() const
133133
}
134134

135135
/*!
136-
Checks if the specified option exists.
136+
Gets a reference to the specified option.
137137
138138
\param key is the name of the option
139-
\result True is the option exists, false otherwise.
139+
\result A reference to the specified option.
140140
*/
141-
bool Config::hasOption(const std::string &key) const
141+
Config::Option & Config::getOption(const std::string &key)
142142
{
143-
return (m_options->count(key) > 0);
143+
return const_cast<Option &>(static_cast<const Config &>(*this).getOption(key));
144+
}
145+
146+
/*!
147+
Gets a constant reference to the specified option.
148+
149+
\param key is the name of the option
150+
\result A constant reference to the specified option.
151+
*/
152+
const Config::Option & Config::getOption(const std::string &key) const
153+
{
154+
return (*m_options).at(key);
144155
}
145156

146157
/*!
147-
Gets the specified option.
158+
Gets the value of the specified option.
148159
149160
If the option does not exists an exception is thrown.
150161
151162
\param key is the name of the option
152-
\result The specified option.
163+
\result The value of the specified option.
153164
*/
154165
const std::string & Config::get(const std::string &key) const
155166
{
156-
return m_options->at(key);
167+
return getOption(key).value;
157168
}
158169

159170
/*!
160-
Gets the specified option.
171+
Gets the value of the specified option.
161172
162173
If the option does not exists the fallback value is returned.
163174
164175
\param key is the name of the option
165176
\param fallback is the value that will be returned if the specified
166177
options does not exist
167-
\result The specified option or the fallback value if the specified
178+
\result The value of the specified option or the fallback value if the
168179
options does not exist.
169180
*/
170181
std::string Config::get(const std::string &key, const std::string &fallback) const
171182
{
172183
if (hasOption(key)) {
173-
return get(key);
184+
return getOption(key).value;
174185
} else {
175186
return fallback;
176187
}
177188
}
178189

179190
/*!
180-
Set the given option to the specified value
191+
Set the value of the specified option.
192+
193+
If the option does not exists, a new option will be added.
181194
182195
\param key is the name of the option
183196
\param value is the value of the option
184197
*/
185198
void Config::set(const std::string &key, const std::string &value)
186199
{
187-
(*m_options)[key] = value;
200+
if (hasOption(key)) {
201+
getOption(key).value = value;
202+
} else {
203+
addOption(key, value);
204+
}
205+
}
206+
207+
/*!
208+
Gets the value of the specified option attribute.
209+
210+
If the option or the attribute does not exists, an exception is thrown.
211+
212+
\param key is the name of the option
213+
\param name is the name of the attribute
214+
\result The value of the specified attribute.
215+
*/
216+
std::string Config::getAttribute(const std::string &key, const std::string &name) const
217+
{
218+
return getOption(key).attributes.at(name);
219+
}
220+
221+
/*!
222+
Gets the value of the specified option attribute.
223+
224+
If the option does not exists, an exception will be thrown. However, if
225+
the attribute do not exists, the fallback walue will be returned
226+
227+
\param key is the name of the option
228+
\param name is the name of the attribute
229+
\param fallback is the value that will be returned if the specified
230+
attribute does not exist
231+
\result The value of the specified attribute or the fallback value if
232+
the options or the attribute does not exist.
233+
*/
234+
std::string Config::getAttribute(const std::string &key, const std::string &name, const std::string &fallback) const
235+
{
236+
const Option &option = getOption(key);
237+
if (option.attributes.count(name) > 0) {
238+
return option.attributes.at(name);
239+
}
240+
241+
return fallback;
242+
}
243+
244+
/*!
245+
Set the value of the specified option attribute.
246+
247+
If the option does not exists, an exception will be thrown. However,
248+
if the attribute does not exists, a new attribute will be added.
249+
250+
\param key is the name of the option
251+
\param name is the name of the attribute
252+
\param value is the value of the attribute
253+
*/
254+
void Config::setAttribute(const std::string &key, const std::string &name, const std::string &value)
255+
{
256+
getOption(key).attributes[name] = value;
257+
}
258+
259+
/*!
260+
Checks if the specified option exists.
261+
262+
\param key is the name of the option
263+
\result True is the option exists, false otherwise.
264+
*/
265+
bool Config::hasOption(const std::string &key) const
266+
{
267+
return (m_options->count(key) > 0);
268+
}
269+
270+
/*!
271+
Add an option to the configuration storage.
272+
273+
If an option with the same key already exists, it will be overwritten.
274+
275+
\param key is the name of the option
276+
\param option is the option that will be added
277+
*/
278+
void Config::addOption(const std::string &key, const Option &option)
279+
{
280+
(*m_options)[key] = option;
281+
}
282+
283+
/*!
284+
Add an option to the configuration storage.
285+
286+
If an option with the same key already exists, it will be overwritten.
287+
288+
\param key is the name of the option
289+
\param option is the option that will be added
290+
*/
291+
void Config::addOption(const std::string &key, Option &&option)
292+
{
293+
(*m_options)[key] = std::move(option);
294+
}
295+
296+
/*!
297+
Add an option to the configuration storage.
298+
299+
If an option with the same key already exists, it will be overwritten.
300+
301+
\param key is the name of the option
302+
\param value is the value of the option
303+
*/
304+
void Config::addOption(const std::string &key, const std::string &value)
305+
{
306+
addOption(key, std::string(value), Attributes());
307+
}
308+
309+
/*!
310+
Add an option to the configuration storage.
311+
312+
If an option with the same key already exists, it will be overwritten.
313+
314+
\param key is the name of the option
315+
\param value is the value of the option
316+
*/
317+
void Config::addOption(const std::string &key, std::string &&value)
318+
{
319+
addOption(key, std::move(value), Attributes());
320+
}
321+
322+
/*!
323+
Add an option to the configuration storage.
324+
325+
If an option with the same key already exists, it will be overwritten.
326+
327+
\param key is the name of the option
328+
\param value is the value of the option
329+
\param attributes are the attributes of the option
330+
*/
331+
void Config::addOption(const std::string &key, const std::string &value, const Attributes &attributes)
332+
{
333+
Option option;
334+
option.value = value;
335+
option.attributes = attributes;
336+
337+
addOption(key, std::move(option));
338+
}
339+
340+
/*!
341+
Add an option to the configuration storage.
342+
343+
If an option with the same key already exists, it will be overwritten.
344+
345+
\param key is the name of the option
346+
\param value is the value of the option
347+
\param attributes are the attributes of the option
348+
*/
349+
void Config::addOption(const std::string &key, std::string &&value, Attributes &&attributes)
350+
{
351+
Option option;
352+
option.value = std::move(value);
353+
option.attributes = std::move(attributes);
354+
355+
addOption(key, std::move(option));
188356
}
189357

190358
/*!
@@ -402,7 +570,23 @@ void Config::dump(std::ostream &out, int indentLevel) const
402570
out << indent << "Options..." << std::endl;
403571
if (getOptionCount() > 0) {
404572
for (const auto &entry : getOptions()) {
405-
out << indent << padding << entry.first << " = " << entry.second << std::endl;
573+
const std::string &key = entry.first;
574+
const Option &option = entry.second;
575+
576+
// Option value
577+
out << indent << padding << key << " = " << option.value << std::endl;
578+
579+
// Option attributes
580+
if (!option.attributes.empty()) {
581+
for (const auto &attributeEntry : option.attributes) {
582+
const std::string &name = attributeEntry.first;
583+
const std::string &value = attributeEntry.second;
584+
585+
out << indent << padding << padding << "Attribute: " << name << " = " << value << std::endl;
586+
}
587+
} else {
588+
out << indent << padding << padding << "Option has not attributes." << std::endl;
589+
}
406590
}
407591
} else {
408592
out << indent << padding << "No options." << std::endl;

0 commit comments

Comments
 (0)