Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
xmlutils.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19/*! \file ored/utilities/xmlutils.cpp
20 \brief
21 \ingroup utilities
22*/
23
28
29#include <boost/lexical_cast.hpp>
30#include <boost/algorithm/string/join.hpp>
31#include <boost/algorithm/string/erase.hpp>
32
33// we only want to include these here.
34#if defined(__clang__)
35#pragma clang diagnostic push
36#pragma clang diagnostic ignored "-Wsuggest-override"
37#endif
38#if defined(__GNUC__)
39#pragma GCC diagnostic push
40#pragma GCC diagnostic ignored "-Wsuggest-override"
41#endif
42#include <rapidxml.hpp>
43#include <rapidxml_print.hpp>
44#if defined(__clang__)
45#pragma clang diagnostic pop
46#endif
47#if defined(__GNUC__)
48#pragma GCC diagnostic pop
49#endif
50
51#include <algorithm>
52#include <fstream>
53
54using namespace std;
55using namespace rapidxml;
56using QuantLib::Size;
57
58namespace ore {
59namespace data {
60
61namespace {
62
63// handle rapid xml parser errors
64
65void handle_rapidxml_parse_error(const rapidxml::parse_error& e) {
66 string where = e.where<char>();
67 boost::erase_all(where, "\n");
68 boost::erase_all(where, "\r");
69 QL_FAIL("RapidXML Parse Error (" << e.what() << ") at '" << where.substr(0, 400) << "'");
70}
71
72
73} // namespace
74
75XMLDocument::XMLDocument() : _doc(new rapidxml::xml_document<char>()), _buffer(NULL) {}
76
77XMLDocument::XMLDocument(const string& fileName) : _doc(new rapidxml::xml_document<char>()), _buffer(NULL) {
78 // Need to load the entire file into memory to pass to doc.parse().
79 ifstream t(fileName.c_str());
80 QL_REQUIRE(t.is_open(), "Failed to open file " << fileName);
81 t.seekg(0, std::ios::end); // go to the end
82 Size length = static_cast<Size>(t.tellg()); // report location (this is the length)
83 QL_REQUIRE(length > 0, "File " << fileName << " is empty.");
84 t.seekg(0, std::ios::beg); // go back to the beginning
85 _buffer = new char[length + 1]; // allocate memory for a buffer of appropriate dimension
86 t.read(_buffer, length); // read the whole file into the buffer
87 _buffer[static_cast<int>(t.gcount())] = '\0';
88 t.close(); // close file handle
89 try {
90 _doc->parse<0>(_buffer);
91 } catch (const rapidxml::parse_error& pe) {
92 handle_rapidxml_parse_error(pe);
93 }
94}
95
97 if (_buffer != NULL)
98 delete[] _buffer;
99 if (_doc != NULL)
100 delete _doc;
101}
102
103void XMLDocument::fromXMLString(const string& xmlString) {
104 QL_REQUIRE(!_buffer, "XML Document is already loaded");
105 Size length = xmlString.size();
106 _buffer = new char[length + 1];
107 strcpy(_buffer, xmlString.c_str());
108 _buffer[length] = '\0';
109 try {
110 _doc->parse<0>(_buffer);
111 } catch (const rapidxml::parse_error& pe) {
112 handle_rapidxml_parse_error(pe);
113 }
114}
115
116XMLNode* XMLDocument::getFirstNode(const string& name) const { return _doc->first_node(name == "" ? NULL : name.c_str()); }
117
118void XMLDocument::appendNode(XMLNode* node) { _doc->append_node(node); }
119
120void XMLDocument::toFile(const string& fileName) const {
121 std::ofstream ofs(fileName.c_str());
122 ofs << *_doc;
123 ofs.close();
124}
125
126string XMLDocument::toString() const {
127 ostringstream oss;
128 oss << *_doc;
129 return oss.str();
130}
131
132XMLNode* XMLDocument::allocNode(const string& nodeName) {
133 XMLNode* n = _doc->allocate_node(node_element, allocString(nodeName));
134 QL_REQUIRE(n, "Failed to allocate XMLNode for " << nodeName);
135 return n;
136}
137
138XMLNode* XMLDocument::allocNode(const string& nodeName, const string& nodeValue) {
139 XMLNode* n = _doc->allocate_node(node_element, allocString(nodeName), allocString(nodeValue));
140 QL_REQUIRE(n, "Failed to allocate XMLNode for " << nodeName);
141 return n;
142}
143
144char* XMLDocument::allocString(const string& str) {
145 char* s = _doc->allocate_string(str.c_str());
146 QL_REQUIRE(s, "Failed to allocate string for " << str);
147 return s;
148}
149
150void XMLSerializable::fromFile(const string& filename) {
151 XMLDocument doc(filename);
152 fromXML(doc.getFirstNode(""));
153}
154
155void XMLSerializable::toFile(const string& filename) const {
156 XMLDocument doc;
157 XMLNode* node = toXML(doc);
158 doc.appendNode(node);
159 doc.toFile(filename);
160}
161
162void XMLSerializable::fromXMLString(const string& xml) {
164 doc.fromXMLString(xml);
165 fromXML(doc.getFirstNode(""));
166}
167
169 XMLDocument doc;
170 XMLNode* node = toXML(doc);
171 doc.appendNode(node);
172 return doc.toString();
173}
174
175void XMLUtils::checkNode(XMLNode* node, const string& expectedName) {
176 QL_REQUIRE(node, "XML Node is NULL (expected " << expectedName << ")");
177 QL_REQUIRE(node->name() == expectedName,
178 "XML Node name " << node->name() << " does not match expected name " << expectedName);
179}
180
181XMLNode* XMLUtils::addChild(XMLDocument& doc, XMLNode* parent, const string& name) {
182 QL_REQUIRE(parent, "XML Parent Node is NULL (adding Child " << name << ")");
183 XMLNode* node = doc.allocNode(name);
184 parent->insert_node(0, node);
185 return node;
186}
187
188void XMLUtils::addChild(XMLDocument& doc, XMLNode* n, const string& name, const char* value) {
189 addChild(doc, n, name, string(value));
190}
191
192void XMLUtils::addChild(XMLDocument& doc, XMLNode* n, const string& name, const string& value) {
193 if (value.empty()) {
194 addChild(doc, n, name);
195 } else {
196 XMLNode* node = doc.allocNode(name, value);
197 QL_REQUIRE(n, "XML Node is NULL (adding " << name << ")");
198 n->insert_node(0, node);
199 }
200}
201
202void XMLUtils::addChildAsCdata(XMLDocument& doc, XMLNode* n, const string& name, const string& value) {
203 if (value.empty()) {
204 addChild(doc, n, name);
205 } else {
206 QL_REQUIRE(n, "XML Node is NULL (adding " << name << ")");
207 XMLNode* node = doc.allocNode(name);
208 n->insert_node(0, node);
209 XMLNode* cdata_node = doc.doc()->allocate_node(node_cdata);
210 cdata_node->value(doc.allocString(value));
211 QL_REQUIRE(cdata_node, "Failed to allocate cdata node for " << name);
212 node->insert_node(0, cdata_node);
213 }
214}
215
216void XMLUtils::addChild(XMLDocument& doc, XMLNode* n, const string& name, const string& value, const string& attrName,
217 const string& attr) {
218 if (!attrName.empty() || !attr.empty()) {
219 addChild(doc, n, name, value, std::vector<string>{attrName}, std::vector<string>{attr});
220 } else {
221 addChild(doc, n, name, value, std::vector<string>{}, std::vector<string>{});
222 }
223}
224
225void XMLUtils::addChild(XMLDocument& doc, XMLNode* n, const string& name, const string& value,
226 const vector<string>& attrNames, const vector<string>& attrs) {
227 QL_REQUIRE(attrNames.size() == attrs.size(), "The size of attrNames should be the same as the size of attrs.");
228 XMLNode* node;
229 if (value.empty()) {
230 node = addChild(doc, n, name);
231 } else {
232 node = doc.allocNode(name, value);
233 QL_REQUIRE(n, "XML Node is NULL (adding " << name << ")");
234 n->insert_node(0, node);
235 }
236 for (Size i = 0; i < attrNames.size(); ++i) {
237 XMLUtils::addAttribute(doc, node, attrNames[i], attrs[i]);
238 }
239}
240
241void XMLUtils::addChild(XMLDocument& doc, XMLNode* n, const string& name, Real value) {
243}
244
245void XMLUtils::addChild(XMLDocument& doc, XMLNode* n, const string& name, int value) {
246 addChild(doc, n, name, std::to_string(value));
247}
248
249void XMLUtils::addChild(XMLDocument& doc, XMLNode* n, const string& name, bool value) {
250 string s = value ? "true" : "false";
251 addChild(doc, n, name, s);
252}
253
254void XMLUtils::addChild(XMLDocument& doc, XMLNode* n, const string& name, const Period& value) {
256}
257
258void XMLUtils::addChild(XMLDocument& doc, XMLNode* parent, const string& name, const vector<Real>& values) {
259 vector<string> strings(values.size());
260 std::transform(values.begin(), values.end(), strings.begin(), [](Real x) { return convertToString(x); });
261 addChild(doc, parent, name, boost::algorithm::join(strings, ","));
262}
263
264void XMLUtils::addChildren(XMLDocument& doc, XMLNode* parent, const string& names, const string& name,
265 const string& firstName, const string& secondName, const map<string, string>& values) {
266 QL_REQUIRE(parent, "XML Node is null (Adding " << names << ")");
267 XMLNode* node = addChild(doc, parent, names);
268 map<string, string>::const_iterator it;
269 for (it = values.begin(); it != values.end(); ++it) {
270 XMLNode* n = addChild(doc, node, name);
271 QL_REQUIRE(n, "XML AllocNode failure (" << name << ")");
272 addChild(doc, n, firstName, it->first);
273 addChild(doc, n, secondName, it->second);
274 }
275}
276
277string XMLUtils::getChildValue(XMLNode* node, const string& name, bool mandatory, const string& defaultValue) {
278 QL_REQUIRE(node, "XMLNode is NULL (was looking for child " << name << ")");
279 xml_node<>* child = node->first_node(name.c_str());
280 if (mandatory) {
281 QL_REQUIRE(child, "Error: No XML Child Node " << name << " found.");
282 }
283 return child ? getNodeValue(child) : defaultValue;
284}
285
286Real XMLUtils::getChildValueAsDouble(XMLNode* node, const string& name, bool mandatory, double defaultValue) {
287 string s = getChildValue(node, name, mandatory);
288 return s == "" ? defaultValue : parseReal(s);
289}
290
291int XMLUtils::getChildValueAsInt(XMLNode* node, const string& name, bool mandatory, int defaultValue) {
292 string s = getChildValue(node, name, mandatory);
293 return s == "" ? defaultValue : parseInteger(s);
294}
295
296bool XMLUtils::getChildValueAsBool(XMLNode* node, const string& name, bool mandatory, bool defaultValue) {
297 string s = getChildValue(node, name, mandatory);
298 return s == "" ? defaultValue : parseBool(s);
299}
300
301Period XMLUtils::getChildValueAsPeriod(XMLNode* node, const string& name, bool mandatory, const Period& defaultValue) {
302 string s = getChildValue(node, name, mandatory);
303 return s == "" ? defaultValue : parsePeriod(s);
304}
305
306vector<string> XMLUtils::getChildrenValues(XMLNode* parent, const string& names, const string& name, bool mandatory) {
307 vector<string> vec;
308 xml_node<>* node = parent->first_node(names.c_str());
309 if (mandatory) {
310 QL_REQUIRE(node, "Error: No XML Node " << names << " found.");
311 }
312 if (node) {
313 for (xml_node<>* child = node->first_node(name.c_str()); child; child = child->next_sibling(name.c_str()))
314 vec.push_back(getNodeValue(child));
315 }
316 return vec;
317}
318
319vector<Real> XMLUtils::getChildrenValuesAsDoubles(XMLNode* node, const string& names, const string& name,
320 bool mandatory) {
321 vector<string> vecS = getChildrenValues(node, names, name, mandatory);
322 vector<Real> vecD(vecS.size());
323 std::transform(vecS.begin(), vecS.end(), vecD.begin(), parseReal);
324 return vecD;
325}
326
327vector<Real> XMLUtils::getChildrenValuesAsDoublesCompact(XMLNode* node, const string& name, bool mandatory) {
328 string s = getChildValue(node, name, mandatory);
329 return parseListOfValues(s, std::function<Real(string)>(&parseReal));
330}
331
333 string s = getNodeValue(node);
334 return parseListOfValues(s, std::function<Real(string)>(&parseReal));
335}
336
337vector<Period> XMLUtils::getChildrenValuesAsPeriods(XMLNode* node, const string& name, bool mandatory) {
338 string s = getChildValue(node, name, mandatory);
339 return parseListOfValues(s, std::function<Period(string)>(&parsePeriod));
340}
341
342vector<string> XMLUtils::getChildrenValuesAsStrings(XMLNode* node, const string& name, bool mandatory) {
343 string s = getChildValue(node, name, mandatory);
344 return parseListOfValues(s);
345}
346
347map<string, string> XMLUtils::getChildrenValues(XMLNode* parent, const string& names, const string& name,
348 const string& firstName, const string& secondName, bool mandatory) {
349 map<string, string> res;
350 xml_node<>* node = parent->first_node(names.c_str());
351 if (mandatory) {
352 QL_REQUIRE(node, "Error: No XML Node " << names << " found.");
353 }
354 if (node) {
355 for (xml_node<>* child = node->first_node(name.c_str()); child; child = child->next_sibling(name.c_str())) {
356 string first = getChildValue(child, firstName, mandatory);
357 string second = getChildValue(child, secondName, mandatory);
358 // res[first] = second;
359 res.insert(pair<string, string>(first, second));
360 }
361 }
362 return res;
363}
364
365map<string, string> XMLUtils::getChildrenAttributesAndValues(XMLNode* parent, const string& names,
366 const string& attributeName, bool mandatory) {
367 map<string, string> res;
368 for (XMLNode* child = getChildNode(parent, names.c_str()); child;
369 child = XMLUtils::getNextSibling(child, names.c_str())) {
370 string first = getAttribute(child, attributeName);
371 string second = getNodeValue(child);
372 if (first.empty())
373 continue;
374 auto it = res.find(first);
375 if (it != res.end())
376 WLOG("XMLUtils::getChildrenAttributesAndValues: Duplicate entry " << first <<
377 " in node " << names << ". Overwritting with value " << second << ".");
378 res.insert(pair<string, string>(first, second));
379 }
380 if (mandatory) {
381 QL_REQUIRE(!res.empty(), "Error: No XML Node " << names << " found.");
382 }
383 return res;
384}
385
386// returns first child node
388 QL_REQUIRE(n, "XMLUtils::getChildNode(" << name << "): XML Node is NULL");
389 return n->first_node(name == "" ? nullptr : name.c_str());
390}
391
392// return first node in the hierarchy of n that matches name, maybe n itself
394 QL_REQUIRE(n, "XMLUtils::locateNode(" << name << "): XML Node is NULL");
395 if (n->name() == name)
396 return n;
397 else {
398 const char* p = name.empty() ? nullptr : name.c_str();
399 XMLNode* node = n->first_node(p);
400 QL_REQUIRE(node, "XML node with name " << name << " not found");
401 return node;
402 }
403}
404
405// append child to parent
406void XMLUtils::appendNode(XMLNode* parent, XMLNode* child) {
407 QL_REQUIRE(parent, "XMLUtils::appendNode() parent is NULL");
408 QL_REQUIRE(child, "XMLUtils::appendNode() child is NULL");
409 parent->append_node(child);
410}
411
412void XMLUtils::addAttribute(XMLDocument& doc, XMLNode* node, const string& attrName, const string& attrValue) {
413 QL_REQUIRE(node, "XMLUtils::appendAttribute(" << attrName << "," << attrName << ") node is NULL");
414 char* name = doc.allocString(attrName.c_str());
415 char* value = doc.allocString(attrValue.c_str());
416 node->append_attribute(doc.doc()->allocate_attribute(name, value));
417}
418
419string XMLUtils::getAttribute(XMLNode* node, const string& attrName) {
420 QL_REQUIRE(node, "XMLUtils::getAttribute(" << attrName << ") node is NULL");
421 xml_attribute<>* attr = node->first_attribute(attrName.c_str());
422 if (attr && attr->value())
423 return string(attr->value());
424 else
425 return "";
426}
427
428vector<XMLNode*> XMLUtils::getChildrenNodes(XMLNode* node, const string& name) {
429 QL_REQUIRE(node, "XMLUtils::getChildrenNodes(" << name << ") node is NULL");
430 vector<XMLNode*> res;
431 const char* p = name.empty() ? nullptr : name.c_str();
432 for (xml_node<>* c = node->first_node(p); c; c = c->next_sibling(p))
433 res.push_back(c);
434 return res;
435}
436
437vector<XMLNode*> XMLUtils::getChildrenNodesWithAttributes(XMLNode* parent, const string& names, const string& name,
438 const string& attrName, vector<string>& attrs,
439 bool mandatory) {
440 std::vector<std::reference_wrapper<vector<string>>> attrs_v;
441 attrs_v.push_back(attrs);
442 return getChildrenNodesWithAttributes(parent, names, name, {attrName}, attrs_v, mandatory);
443}
444
445vector<XMLNode*> XMLUtils::getChildrenNodesWithAttributes(XMLNode* parent, const string& names, const string& name,
446 const vector<string>& attrNames,
447 const vector<std::reference_wrapper<vector<string>>>& attrs,
448 bool mandatory) {
449 QL_REQUIRE(attrNames.size() == attrs.size(),
450 "attrNames size (" << attrNames.size() << ") must match attrs size (" << attrs.size() << ")");
451 vector<XMLNode*> vec;
452 // if names is empty, use the parent as the anchor node
453 rapidxml::xml_node<>* node = names.empty() ? parent : parent->first_node(names.c_str());
454 if (mandatory) {
455 QL_REQUIRE(node, "Error: No XML Node " << names << " found.");
456 }
457 if (node) {
458 for (rapidxml::xml_node<>* child = node->first_node(name.c_str()); child;
459 child = child->next_sibling(name.c_str())) {
460 vec.push_back(child);
461 for (Size i = 0; i < attrNames.size(); ++i) {
462 xml_attribute<>* attr = child->first_attribute(attrNames[i].c_str());
463 if (attr && attr->value())
464 ((vector<string>&)attrs[i]).push_back(attr->value());
465 else
466 ((vector<string>&)attrs[i]).push_back("");
467 }
468 }
469 }
470 return vec;
471}
472
474 QL_REQUIRE(node, "XMLUtils::getNodeName(): XML Node is NULL");
475 return node->name();
476}
477
478void XMLUtils::setNodeName(XMLDocument& doc, XMLNode* node, const string& name) {
479 QL_REQUIRE(node, "XMLUtils::setNodeName(" << name << "): XML Node is NULL");
480 char* nodeName = doc.allocString(name);
481 node->name(nodeName);
482}
483
485 QL_REQUIRE(node, "XMLUtils::getNextSibling(" << name << "): XML Node is NULL");
486 return node->next_sibling(name == "" ? nullptr : name.c_str());
487}
488
490 QL_REQUIRE(node, "XMLUtils::getNodeValue(): XML Node is NULL");
491 // handle CDATA nodes
492 XMLNode* n = node->first_node();
493 if (n && n->type() == node_cdata)
494 return n->value();
495 // all other cases
496 return node->value();
497}
498
499// template implementations
500
501template <class T>
502void XMLUtils::addChildren(XMLDocument& doc, XMLNode* parent, const string& names, const string& name,
503 const vector<T>& values) {
504 XMLNode* node = addChild(doc, parent, names);
505 for (Size i = 0; i < values.size(); i++)
506 addChild(doc, node, name, values[i]);
507}
508
509template <class T>
510void XMLUtils::addChildrenWithAttributes(XMLDocument& doc, XMLNode* parent, const string& names, const string& name,
511 const vector<T>& values, const string& attrName, const vector<string>& attrs) {
512 addChildrenWithAttributes(doc, parent, names, name, values, vector<string>{attrName},
513 vector<vector<string>>{attrs});
514}
515
516template <class T>
517void XMLUtils::addChildrenWithAttributes(XMLDocument& doc, XMLNode* parent, const string& names, const string& name,
518 const vector<T>& values, const vector<string>& attrNames,
519 const vector<vector<string>>& attrs) {
520 QL_REQUIRE(attrNames.size() == attrs.size(),
521 "attrNames size (" << attrNames.size() << ") must match attrs size (" << attrs.size() << ")");
522 if (values.size() > 0) {
523 for (auto const& attr : attrs) {
524 QL_REQUIRE(values.size() == attr.size(), "Values / Attribute vector size mismatch");
525 }
526 QL_REQUIRE(parent, "XML Node is null (Adding " << names << ")");
527 XMLNode* node = addChild(doc, parent, names);
528 for (Size i = 0; i < values.size(); i++) {
529 XMLNode* c = doc.allocNode(name, convertToString(values[i]));
530 QL_REQUIRE(c, "XML AllocNode failure (" << name << ")");
531 QL_REQUIRE(node, "XML Node is NULL (" << name << ")");
532 node->insert_node(0, c);
533 for (Size j = 0; j < attrs.size(); ++j) {
534 if (attrs[j][i] != "")
535 addAttribute(doc, c, attrNames[j], attrs[j][i]);
536 }
537 }
538 }
539}
540
541template <class T>
542void XMLUtils::addChildrenWithOptionalAttributes(XMLDocument& doc, XMLNode* n, const string& names, const string& name,
543 const vector<T>& values, const string& attrName,
544 const vector<string>& attrs) {
545 addChildrenWithOptionalAttributes(doc, n, names, name, values, vector<string>{attrName},
546 vector<vector<string>>{attrs});
547}
548
549template <class T>
550void XMLUtils::addChildrenWithOptionalAttributes(XMLDocument& doc, XMLNode* n, const string& names, const string& name,
551 const vector<T>& values, const vector<string>& attrNames,
552 const vector<vector<string>>& attrs) {
553 QL_REQUIRE(attrNames.size() == attrs.size(),
554 "attrNames size (" << attrNames.size() << ") must match attrs size (" << attrs.size() << ")");
555 for (auto const& attr : attrs)
556 QL_REQUIRE(attr.empty() == attrs.front().empty(), "all attributes must be empty or non-empty at the same time");
557 if (attrs.empty() || attrs.front().empty())
558 XMLUtils::addChildren(doc, n, names, name, values);
559 else
560 XMLUtils::addChildrenWithAttributes(doc, n, names, name, values, attrNames, attrs);
561}
562
563vector<string> XMLUtils::getChildrenValuesWithAttributes(XMLNode* parent, const string& names, const string& name,
564 const string& attrName, vector<string>& attrs,
565 bool mandatory) {
566 return getChildrenValuesWithAttributes<string>(
567 parent, names, name, attrName, attrs, [](const string& x) { return x; }, mandatory);
568}
569
570template <class T>
571vector<T> XMLUtils::getChildrenValuesWithAttributes(XMLNode* parent, const string& names, const string& name,
572 const string& attrName, vector<string>& attrs,
573 const std::function<T(string)> parser, bool mandatory) {
574 std::vector<std::reference_wrapper<vector<string>>> attrs_v;
575 attrs_v.push_back(attrs);
576 return getChildrenValuesWithAttributes(parent, names, name, vector<string>{attrName}, attrs_v, parser, mandatory);
577}
578
579vector<string> XMLUtils::getChildrenValuesWithAttributes(XMLNode* parent, const string& names, const string& name,
580 const vector<string>& attrNames,
581 const vector<std::reference_wrapper<vector<string>>>& attrs,
582 bool mandatory) {
583 return getChildrenValuesWithAttributes<string>(
584 parent, names, name, attrNames, attrs, [](const string& x) { return x; }, mandatory);
585}
586
587template <class T>
588vector<T> XMLUtils::getChildrenValuesWithAttributes(XMLNode* parent, const string& names, const string& name,
589 const vector<string>& attrNames,
590 const vector<std::reference_wrapper<vector<string>>>& attrs,
591 const std::function<T(string)> parser, bool mandatory) {
592 QL_REQUIRE(parser, "XMLUtils::getChildrenValuesWithAttributes(): parser is null");
593 QL_REQUIRE(attrNames.size() == attrs.size(),
594 "attrNames size (" << attrNames.size() << ") must match attrs size (" << attrs.size() << ")");
595 vector<T> vec;
596 // if 'names' is not given, use the parent node directly
597 rapidxml::xml_node<>* node = names.empty() ? parent : parent->first_node(names.c_str());
598 if (mandatory) {
599 QL_REQUIRE(node, "Error: No XML Node " << names << " found.");
600 }
601 if (node) {
602 for (rapidxml::xml_node<>* child = node->first_node(name.c_str()); child;
603 child = child->next_sibling(name.c_str())) {
604
605 std::string vstr = getNodeValue(child);
606 vec.push_back(parser(vstr));
607
608 for (Size i = 0; i < attrNames.size(); ++i) {
609 xml_attribute<>* attr = child->first_attribute(attrNames[i].c_str());
610 if (attr && attr->value())
611 ((vector<string>&)attrs[i]).push_back(attr->value());
612 else
613 ((vector<string>&)attrs[i]).push_back("");
614 }
615 }
616 }
617 return vec;
618}
619
621 // We want to write out a double that conforms to xs:double, this means no
622 // scientific notation, so we check for really small numbers here and explicitly set
623 // to 16 decimal places
624 string result;
625 if (std::abs(value) < 1.0e-6) {
626 std::ostringstream obj1;
627 obj1.precision(16);
628 obj1 << std::fixed << value;
629 result = obj1.str();
630 } else {
631 // And here we just use boost::lexical_cast which is better
632 // at precision than std::to_string()
633 result = boost::lexical_cast<std::string>(value);
634 }
635 return result;
636}
637
638template <class T> string XMLUtils::convertToString(const T& value) { return boost::lexical_cast<std::string>(value); }
639
640/* Instantiate some template functions above for types T we want to support. Add instantiations for more types here,
641 if required. This has two advantages over putting the templated version of the functions in the header file:
642 - faster compile times
643 - we do not need to include the rapid xml headers in xmlutils.hpp */
644
645template void XMLUtils::addChildren(XMLDocument& doc, XMLNode* parent, const string& names, const string& name,
646 const vector<string>& values);
647// throws a warning currently, but that is ok, see the FIXME above in template <> void XMLUtils::addChildren(...)
648// template void XMLUtils::addChildren(XMLDocument& doc, XMLNode* parent, const string& names, const string& name,
649// const vector<double>& values);
650template void XMLUtils::addChildren(XMLDocument& doc, XMLNode* parent, const string& names, const string& name,
651 const vector<Real>& values);
652template void XMLUtils::addChildren(XMLDocument& doc, XMLNode* parent, const string& names, const string& name,
653 const vector<bool>& values);
654
655template void XMLUtils::addChildrenWithAttributes(XMLDocument& doc, XMLNode* parent, const string& names,
656 const string& name, const vector<string>& values,
657 const string& attrName, const vector<string>& attrs);
658template void XMLUtils::addChildrenWithAttributes(XMLDocument& doc, XMLNode* parent, const string& names,
659 const string& name, const vector<double>& values,
660 const string& attrName, const vector<string>& attrs);
661template void XMLUtils::addChildrenWithAttributes(XMLDocument& doc, XMLNode* parent, const string& names,
662 const string& name, const vector<bool>& values,
663 const string& attrName, const vector<string>& attrs);
664
665template void XMLUtils::addChildrenWithAttributes(XMLDocument& doc, XMLNode* parent, const string& names,
666 const string& name, const vector<string>& values,
667 const vector<string>& attrNames, const vector<vector<string>>& attrs);
668template void XMLUtils::addChildrenWithAttributes(XMLDocument& doc, XMLNode* parent, const string& names,
669 const string& name, const vector<double>& values,
670 const vector<string>& attrNames, const vector<vector<string>>& attrs);
671template void XMLUtils::addChildrenWithAttributes(XMLDocument& doc, XMLNode* parent, const string& names,
672 const string& name, const vector<bool>& values,
673 const vector<string>& attrNames, const vector<vector<string>>& attrs);
674
675template void XMLUtils::addChildrenWithOptionalAttributes(XMLDocument& doc, XMLNode* n, const string& names,
676 const string& name, const vector<string>& values,
677 const string& attrName, const vector<string>& attrs);
678template void XMLUtils::addChildrenWithOptionalAttributes(XMLDocument& doc, XMLNode* n, const string& names,
679 const string& name, const vector<double>& values,
680 const string& attrName, const vector<string>& attrs);
681template void XMLUtils::addChildrenWithOptionalAttributes(XMLDocument& doc, XMLNode* n, const string& names,
682 const string& name, const vector<bool>& values,
683 const string& attrName, const vector<string>& attrs);
684
685template void XMLUtils::addChildrenWithOptionalAttributes(XMLDocument& doc, XMLNode* n, const string& names,
686 const string& name, const vector<string>& values,
687 const vector<string>& attrNames,
688 const vector<vector<string>>& attrs);
689template void XMLUtils::addChildrenWithOptionalAttributes(XMLDocument& doc, XMLNode* n, const string& names,
690 const string& name, const vector<double>& values,
691 const vector<string>& attrNames,
692 const vector<vector<string>>& attrs);
693template void XMLUtils::addChildrenWithOptionalAttributes(XMLDocument& doc, XMLNode* n, const string& names,
694 const string& name, const vector<bool>& values,
695 const vector<string>& attrNames,
696 const vector<vector<string>>& attrs);
697
698template vector<std::string> XMLUtils::getChildrenValuesWithAttributes(XMLNode* parent, const string& names,
699 const string& name, const string& attrName,
700 vector<string>& attrs,
701 std::function<string(string)> parser,
702 bool mandatory);
703
704template vector<double> XMLUtils::getChildrenValuesWithAttributes(XMLNode* parent, const string& names,
705 const string& name, const string& attrName,
706 vector<string>& attrs,
707 std::function<double(string)> parser, bool mandatory);
708template vector<bool> XMLUtils::getChildrenValuesWithAttributes(XMLNode* parent, const string& names,
709 const string& name, const string& attrName,
710 vector<string>& attrs,
711 std::function<bool(string)> parser, bool mandatory);
712
713
715 string xml_as_string;
716 rapidxml::print(std::back_inserter(xml_as_string), *node);
717 return xml_as_string;
718}
719
720} // namespace data
721} // namespace ore
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
void appendNode(XMLNode *)
Definition: xmlutils.cpp:118
XMLDocument()
create an empty doc.
Definition: xmlutils.cpp:75
std::string toString() const
return the XML Document as a string.
Definition: xmlutils.cpp:126
~XMLDocument()
destructor
Definition: xmlutils.cpp:96
rapidxml::xml_document< char > * doc()
Definition: xmlutils.hpp:91
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
void toFile(const string &filename) const
save the XML Document to the given file.
Definition: xmlutils.cpp:120
void fromXMLString(const string &xmlString)
load a document from a hard-coded string
Definition: xmlutils.cpp:103
rapidxml::xml_document< char > * _doc
Definition: xmlutils.hpp:94
XMLNode * getFirstNode(const string &name) const
Definition: xmlutils.cpp:116
char * allocString(const string &str)
Definition: xmlutils.cpp:144
std::string toXMLString() const
Parse from XML string.
Definition: xmlutils.cpp:168
void fromXMLString(const std::string &xml)
Parse from XML string.
Definition: xmlutils.cpp:162
virtual XMLNode * toXML(XMLDocument &doc) const =0
virtual void fromXML(XMLNode *node)=0
void fromFile(const std::string &filename)
Definition: xmlutils.cpp:150
void toFile(const std::string &filename) const
Definition: xmlutils.cpp:155
static void addChildrenWithAttributes(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values, const string &attrName, const vector< string > &attrs)
Definition: xmlutils.cpp:510
static void addAttribute(XMLDocument &doc, XMLNode *node, const string &attrName, const string &attrValue)
Definition: xmlutils.cpp:412
static vector< Real > getChildrenValuesAsDoubles(XMLNode *node, const string &names, const string &name, bool mandatory=false)
Definition: xmlutils.cpp:319
static void addChildren(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values)
Definition: xmlutils.cpp:502
static string getAttribute(XMLNode *node, const string &attrName)
Definition: xmlutils.cpp:419
static void checkNode(XMLNode *n, const string &expectedName)
Definition: xmlutils.cpp:175
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
Definition: xmlutils.cpp:286
static XMLNode * locateNode(XMLNode *n, const string &name="")
Definition: xmlutils.cpp:393
static void addChildAsCdata(XMLDocument &doc, XMLNode *n, const string &name, const string &value)
Definition: xmlutils.cpp:202
static string getNodeName(XMLNode *n)
Get and set a node's name.
Definition: xmlutils.cpp:473
static map< string, string > getChildrenAttributesAndValues(XMLNode *parent, const string &names, const string &attributeName, bool mandatory=false)
Definition: xmlutils.cpp:365
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
Definition: xmlutils.cpp:277
static bool getChildValueAsBool(XMLNode *node, const string &name, bool mandatory=false, bool defaultValue=true)
Definition: xmlutils.cpp:296
static XMLNode * getChildNode(XMLNode *n, const string &name="")
Definition: xmlutils.cpp:387
static void addChildrenWithOptionalAttributes(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values, const string &attrName, const vector< string > &attrs)
Definition: xmlutils.cpp:542
static string getNodeValue(XMLNode *node)
Get a node's value.
Definition: xmlutils.cpp:489
static int getChildValueAsInt(XMLNode *node, const string &name, bool mandatory=false, int defaultValue=0)
Definition: xmlutils.cpp:291
static Period getChildValueAsPeriod(XMLNode *node, const string &name, bool mandatory=false, const QuantLib::Period &defaultValue=0 *QuantLib::Days)
Definition: xmlutils.cpp:301
static XMLNode * getNextSibling(XMLNode *node, const string &name="")
Get a node's next sibling node.
Definition: xmlutils.cpp:484
static vector< string > getChildrenValuesAsStrings(XMLNode *node, const string &name, bool mandatory=false)
Definition: xmlutils.cpp:342
static vector< string > getChildrenValuesWithAttributes(XMLNode *node, const string &names, const string &name, const string &attrName, vector< string > &attrs, bool mandatory=false)
Definition: xmlutils.cpp:563
static vector< Real > getChildrenValuesAsDoublesCompact(XMLNode *node, const string &name, bool mandatory=false)
Definition: xmlutils.cpp:327
static string convertToString(const Real value)
Definition: xmlutils.cpp:620
static vector< string > getChildrenValues(XMLNode *node, const string &names, const string &name, bool mandatory=false)
Definition: xmlutils.cpp:306
static void setNodeName(XMLDocument &doc, XMLNode *node, const string &name)
Definition: xmlutils.cpp:478
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
Definition: xmlutils.cpp:181
static string toString(XMLNode *node)
Write a node out as a string.
Definition: xmlutils.cpp:714
static void appendNode(XMLNode *parent, XMLNode *child)
Definition: xmlutils.cpp:406
static vector< Period > getChildrenValuesAsPeriods(XMLNode *node, const string &name, bool mandatory=false)
Definition: xmlutils.cpp:337
static vector< XMLNode * > getChildrenNodesWithAttributes(XMLNode *node, const string &names, const string &name, const string &attrName, vector< string > &attrs, bool mandatory=false)
Definition: xmlutils.cpp:437
static vector< Real > getNodeValueAsDoublesCompact(XMLNode *node)
Get a node's compact values as vector of doubles.
Definition: xmlutils.cpp:332
XML Document.
Definition: xmlutils.hpp:47
SafeStack< ValueType > value
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
bool parseBool(const string &s)
Convert text to bool.
Definition: parsers.cpp:144
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
Definition: parsers.cpp:136
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
std::vector< string > parseListOfValues(string s, const char escape, const char delim, const char quote)
Definition: parsers.cpp:639
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
string conversion utilities
string name
XML utility functions.