29#include <boost/lexical_cast.hpp>
30#include <boost/algorithm/string/join.hpp>
31#include <boost/algorithm/string/erase.hpp>
35#pragma clang diagnostic push
36#pragma clang diagnostic ignored "-Wsuggest-override"
39#pragma GCC diagnostic push
40#pragma GCC diagnostic ignored "-Wsuggest-override"
42#include <rapidxml.hpp>
43#include <rapidxml_print.hpp>
45#pragma clang diagnostic pop
48#pragma GCC diagnostic pop
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) <<
"'");
79 ifstream t(fileName.c_str());
80 QL_REQUIRE(t.is_open(),
"Failed to open file " << fileName);
81 t.seekg(0, std::ios::end);
82 Size length =
static_cast<Size
>(t.tellg());
83 QL_REQUIRE(length > 0,
"File " << fileName <<
" is empty.");
84 t.seekg(0, std::ios::beg);
87 _buffer[
static_cast<int>(t.gcount())] =
'\0';
91 }
catch (
const rapidxml::parse_error& pe) {
92 handle_rapidxml_parse_error(pe);
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());
111 }
catch (
const rapidxml::parse_error& pe) {
112 handle_rapidxml_parse_error(pe);
121 std::ofstream ofs(fileName.c_str());
134 QL_REQUIRE(n,
"Failed to allocate XMLNode for " << nodeName);
140 QL_REQUIRE(n,
"Failed to allocate XMLNode for " << nodeName);
145 char* s =
_doc->allocate_string(str.c_str());
146 QL_REQUIRE(s,
"Failed to allocate string for " << str);
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);
182 QL_REQUIRE(parent,
"XML Parent Node is NULL (adding Child " <<
name <<
")");
184 parent->insert_node(0, node);
197 QL_REQUIRE(n,
"XML Node is NULL (adding " <<
name <<
")");
198 n->insert_node(0, node);
206 QL_REQUIRE(n,
"XML Node is NULL (adding " <<
name <<
")");
208 n->insert_node(0, node);
209 XMLNode* cdata_node = doc.
doc()->allocate_node(node_cdata);
211 QL_REQUIRE(cdata_node,
"Failed to allocate cdata node for " <<
name);
212 node->insert_node(0, cdata_node);
217 const string& attr) {
218 if (!attrName.empty() || !attr.empty()) {
219 addChild(doc, n,
name,
value, std::vector<string>{attrName}, std::vector<string>{attr});
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.");
233 QL_REQUIRE(n,
"XML Node is NULL (adding " <<
name <<
")");
234 n->insert_node(0, node);
236 for (Size i = 0; i < attrNames.size(); ++i) {
250 string s =
value ?
"true" :
"false";
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,
","));
265 const string& firstName,
const string& secondName,
const map<string, string>& values) {
266 QL_REQUIRE(parent,
"XML Node is null (Adding " << names <<
")");
268 map<string, string>::const_iterator it;
269 for (it = values.begin(); it != values.end(); ++it) {
271 QL_REQUIRE(n,
"XML AllocNode failure (" <<
name <<
")");
272 addChild(doc, n, firstName, it->first);
273 addChild(doc, n, secondName, it->second);
278 QL_REQUIRE(node,
"XMLNode is NULL (was looking for child " <<
name <<
")");
281 QL_REQUIRE(child,
"Error: No XML Child Node " <<
name <<
" found.");
288 return s ==
"" ? defaultValue :
parseReal(s);
298 return s ==
"" ? defaultValue :
parseBool(s);
308 xml_node<>* node = parent->first_node(names.c_str());
310 QL_REQUIRE(node,
"Error: No XML Node " << names <<
" found.");
313 for (
xml_node<>* child = node->first_node(
name.c_str()); child; child = child->next_sibling(
name.c_str()))
322 vector<Real> vecD(vecS.size());
323 std::transform(vecS.begin(), vecS.end(), vecD.begin(),
parseReal);
348 const string& firstName,
const string& secondName,
bool mandatory) {
349 map<string, string> res;
350 xml_node<>* node = parent->first_node(names.c_str());
352 QL_REQUIRE(node,
"Error: No XML Node " << names <<
" found.");
355 for (
xml_node<>* child = node->first_node(
name.c_str()); child; child = child->next_sibling(
name.c_str())) {
359 res.insert(pair<string, string>(first, second));
366 const string& attributeName,
bool mandatory) {
367 map<string, string> res;
374 auto it = res.find(first);
376 WLOG(
"XMLUtils::getChildrenAttributesAndValues: Duplicate entry " << first <<
377 " in node " << names <<
". Overwritting with value " << second <<
".");
378 res.insert(pair<string, string>(first, second));
381 QL_REQUIRE(!res.empty(),
"Error: No XML Node " << names <<
" found.");
388 QL_REQUIRE(n,
"XMLUtils::getChildNode(" <<
name <<
"): XML Node is NULL");
389 return n->first_node(
name ==
"" ?
nullptr :
name.c_str());
394 QL_REQUIRE(n,
"XMLUtils::locateNode(" <<
name <<
"): XML Node is NULL");
395 if (n->name() ==
name)
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");
407 QL_REQUIRE(parent,
"XMLUtils::appendNode() parent is NULL");
408 QL_REQUIRE(child,
"XMLUtils::appendNode() child is NULL");
409 parent->append_node(child);
413 QL_REQUIRE(node,
"XMLUtils::appendAttribute(" << attrName <<
"," << attrName <<
") node is NULL");
416 node->append_attribute(doc.
doc()->allocate_attribute(
name,
value));
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());
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))
438 const string& attrName, vector<string>& attrs,
440 std::vector<std::reference_wrapper<vector<string>>> attrs_v;
441 attrs_v.push_back(attrs);
446 const vector<string>& attrNames,
447 const vector<std::reference_wrapper<vector<string>>>& attrs,
449 QL_REQUIRE(attrNames.size() == attrs.size(),
450 "attrNames size (" << attrNames.size() <<
") must match attrs size (" << attrs.size() <<
")");
451 vector<XMLNode*> vec;
455 QL_REQUIRE(node,
"Error: No XML Node " << names <<
" found.");
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());
466 ((vector<string>&)attrs[i]).push_back(
"");
474 QL_REQUIRE(node,
"XMLUtils::getNodeName(): XML Node is NULL");
479 QL_REQUIRE(node,
"XMLUtils::setNodeName(" <<
name <<
"): XML Node is NULL");
481 node->name(nodeName);
485 QL_REQUIRE(node,
"XMLUtils::getNextSibling(" <<
name <<
"): XML Node is NULL");
486 return node->next_sibling(
name ==
"" ?
nullptr :
name.c_str());
490 QL_REQUIRE(node,
"XMLUtils::getNodeValue(): XML Node is NULL");
492 XMLNode* n = node->first_node();
493 if (n && n->type() == node_cdata)
496 return node->value();
503 const vector<T>& values) {
505 for (Size i = 0; i < values.size(); i++)
511 const vector<T>& values,
const string& attrName,
const vector<string>& attrs) {
513 vector<vector<string>>{attrs});
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");
526 QL_REQUIRE(parent,
"XML Node is null (Adding " << names <<
")");
528 for (Size i = 0; i < values.size(); 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] !=
"")
543 const vector<T>& values,
const string& attrName,
544 const vector<string>& attrs) {
546 vector<vector<string>>{attrs});
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())
564 const string& attrName, vector<string>& attrs,
566 return getChildrenValuesWithAttributes<string>(
567 parent, names,
name, attrName, attrs, [](
const string& x) {
return x; }, mandatory);
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);
580 const vector<string>& attrNames,
581 const vector<std::reference_wrapper<vector<string>>>& attrs,
583 return getChildrenValuesWithAttributes<string>(
584 parent, names,
name, attrNames, attrs, [](
const string& x) {
return x; }, mandatory);
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() <<
")");
599 QL_REQUIRE(node,
"Error: No XML Node " << names <<
" found.");
603 child = child->next_sibling(
name.c_str())) {
606 vec.push_back(parser(vstr));
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());
613 ((vector<string>&)attrs[i]).push_back(
"");
625 if (std::abs(
value) < 1.0e-6) {
626 std::ostringstream obj1;
628 obj1 << std::fixed <<
value;
633 result = boost::lexical_cast<std::string>(
value);
646 const vector<string>& values);
651 const vector<Real>& values);
653 const vector<bool>& values);
656 const string&
name,
const vector<string>& values,
657 const string& attrName,
const vector<string>& attrs);
659 const string&
name,
const vector<double>& values,
660 const string& attrName,
const vector<string>& attrs);
662 const string&
name,
const vector<bool>& values,
663 const string& attrName,
const vector<string>& attrs);
666 const string&
name,
const vector<string>& values,
667 const vector<string>& attrNames,
const vector<vector<string>>& attrs);
669 const string&
name,
const vector<double>& values,
670 const vector<string>& attrNames,
const vector<vector<string>>& attrs);
672 const string&
name,
const vector<bool>& values,
673 const vector<string>& attrNames,
const vector<vector<string>>& attrs);
676 const string&
name,
const vector<string>& values,
677 const string& attrName,
const vector<string>& attrs);
679 const string&
name,
const vector<double>& values,
680 const string& attrName,
const vector<string>& attrs);
682 const string&
name,
const vector<bool>& values,
683 const string& attrName,
const vector<string>& attrs);
686 const string&
name,
const vector<string>& values,
687 const vector<string>& attrNames,
688 const vector<vector<string>>& attrs);
690 const string&
name,
const vector<double>& values,
691 const vector<string>& attrNames,
692 const vector<vector<string>>& attrs);
694 const string&
name,
const vector<bool>& values,
695 const vector<string>& attrNames,
696 const vector<vector<string>>& attrs);
699 const string&
name,
const string& attrName,
700 vector<string>& attrs,
701 std::function<
string(
string)> parser,
705 const string&
name,
const string& attrName,
706 vector<string>& attrs,
707 std::function<
double(
string)> parser,
bool mandatory);
709 const string&
name,
const string& attrName,
710 vector<string>& attrs,
711 std::function<
bool(
string)> parser,
bool mandatory);
715 string xml_as_string;
716 rapidxml::print(std::back_inserter(xml_as_string), *node);
717 return xml_as_string;
Small XML Document wrapper class.
void appendNode(XMLNode *)
XMLDocument()
create an empty doc.
std::string toString() const
return the XML Document as a string.
rapidxml::xml_document< char > * doc()
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
void toFile(const string &filename) const
save the XML Document to the given file.
void fromXMLString(const string &xmlString)
load a document from a hard-coded string
rapidxml::xml_document< char > * _doc
XMLNode * getFirstNode(const string &name) const
char * allocString(const string &str)
std::string toXMLString() const
Parse from XML string.
void fromXMLString(const std::string &xml)
Parse from XML string.
virtual XMLNode * toXML(XMLDocument &doc) const =0
virtual void fromXML(XMLNode *node)=0
void fromFile(const std::string &filename)
void toFile(const std::string &filename) const
static void addChildrenWithAttributes(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values, const string &attrName, const vector< string > &attrs)
static void addAttribute(XMLDocument &doc, XMLNode *node, const string &attrName, const string &attrValue)
static vector< Real > getChildrenValuesAsDoubles(XMLNode *node, const string &names, const string &name, bool mandatory=false)
static void addChildren(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values)
static string getAttribute(XMLNode *node, const string &attrName)
static void checkNode(XMLNode *n, const string &expectedName)
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
static XMLNode * locateNode(XMLNode *n, const string &name="")
static void addChildAsCdata(XMLDocument &doc, XMLNode *n, const string &name, const string &value)
static string getNodeName(XMLNode *n)
Get and set a node's name.
static map< string, string > getChildrenAttributesAndValues(XMLNode *parent, const string &names, const string &attributeName, bool mandatory=false)
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
static bool getChildValueAsBool(XMLNode *node, const string &name, bool mandatory=false, bool defaultValue=true)
static XMLNode * getChildNode(XMLNode *n, const string &name="")
static void addChildrenWithOptionalAttributes(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values, const string &attrName, const vector< string > &attrs)
static string getNodeValue(XMLNode *node)
Get a node's value.
static int getChildValueAsInt(XMLNode *node, const string &name, bool mandatory=false, int defaultValue=0)
static Period getChildValueAsPeriod(XMLNode *node, const string &name, bool mandatory=false, const QuantLib::Period &defaultValue=0 *QuantLib::Days)
static XMLNode * getNextSibling(XMLNode *node, const string &name="")
Get a node's next sibling node.
static vector< string > getChildrenValuesAsStrings(XMLNode *node, const string &name, bool mandatory=false)
static vector< string > getChildrenValuesWithAttributes(XMLNode *node, const string &names, const string &name, const string &attrName, vector< string > &attrs, bool mandatory=false)
static vector< Real > getChildrenValuesAsDoublesCompact(XMLNode *node, const string &name, bool mandatory=false)
static string convertToString(const Real value)
static vector< string > getChildrenValues(XMLNode *node, const string &names, const string &name, bool mandatory=false)
static void setNodeName(XMLDocument &doc, XMLNode *node, const string &name)
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
static string toString(XMLNode *node)
Write a node out as a string.
static void appendNode(XMLNode *parent, XMLNode *child)
static vector< Period > getChildrenValuesAsPeriods(XMLNode *node, const string &name, bool mandatory=false)
static vector< XMLNode * > getChildrenNodesWithAttributes(XMLNode *node, const string &names, const string &name, const string &attrName, vector< string > &attrs, bool mandatory=false)
static vector< Real > getNodeValueAsDoublesCompact(XMLNode *node)
Get a node's compact values as vector of doubles.
SafeStack< ValueType > value
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
bool parseBool(const string &s)
Convert text to bool.
Real parseReal(const string &s)
Convert text to Real.
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
Classes and functions for log message handling.
#define WLOG(text)
Logging Macro (Level = Warning)
std::vector< string > parseListOfValues(string s, const char escape, const char delim, const char quote)
std::string to_string(const LocationInfo &l)
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.
string conversion utilities