diff options
Diffstat (limited to 'zenXml/zenxml')
-rw-r--r-- | zenXml/zenxml/cvrt_struc.h | 35 | ||||
-rw-r--r-- | zenXml/zenxml/cvrt_text.h | 32 | ||||
-rw-r--r-- | zenXml/zenxml/dom.h | 78 | ||||
-rw-r--r-- | zenXml/zenxml/parser.h | 6 | ||||
-rw-r--r-- | zenXml/zenxml/xml.h | 181 |
5 files changed, 153 insertions, 179 deletions
diff --git a/zenXml/zenxml/cvrt_struc.h b/zenXml/zenxml/cvrt_struc.h index 9d484f75..a437604c 100644 --- a/zenXml/zenxml/cvrt_struc.h +++ b/zenXml/zenxml/cvrt_struc.h @@ -84,17 +84,17 @@ public: //Conversion from arbitrary types to an XML element enum class ValueType { - STL_CONTAINER, - STL_PAIR, - OTHER, + stlContainer, + stlPair, + other, }; template <class T> using GetValueType = std::integral_constant<ValueType, - GetTextType <T>::value != TEXT_TYPE_OTHER ? ValueType::OTHER : //some string classes are also STL containers, so check this first - IsStlContainer<T>::value ? ValueType::STL_CONTAINER : - IsStlPair <T>::value ? ValueType::STL_PAIR : - ValueType::OTHER>; + GetTextType <T>::value != TextType::other ? ValueType::other : //some string classes are also STL containers, so check this first + IsStlContainer<T>::value ? ValueType::stlContainer : + IsStlPair <T>::value ? ValueType::stlPair : + ValueType::other>; template <class T, ValueType type> @@ -109,7 +109,7 @@ struct ConvertElement; //partial specialization: handle conversion for all STL-container types! template <class T> -struct ConvertElement<T, ValueType::STL_CONTAINER> +struct ConvertElement<T, ValueType::stlContainer> { void writeStruc(const T& value, XmlElement& output) const { @@ -121,19 +121,20 @@ struct ConvertElement<T, ValueType::STL_CONTAINER> } bool readStruc(const XmlElement& input, T& value) const { - bool success = true; value.clear(); - auto itPair = input.getChildren("Item"); - for (auto it = itPair.first; it != itPair.second; ++it) + bool success = true; + const auto itPair = input.getChildren("Item"); + + std::for_each(itPair.first, itPair.second, [&](const XmlElement& xmlChild) { - typename T::value_type childVal; //MSVC 2010 bug: cannot put this into a lambda body - if (zen::readStruc(*it, childVal)) - value.insert(value.end(), childVal); + typename T::value_type childVal; + if (zen::readStruc(xmlChild, childVal)) + value.insert(value.end(), std::move(childVal)); else success = false; //should we support insertion of partially-loaded struct?? - } + }); return success; } }; @@ -141,7 +142,7 @@ struct ConvertElement<T, ValueType::STL_CONTAINER> //partial specialization: handle conversion for std::pair template <class T> -struct ConvertElement<T, ValueType::STL_PAIR> +struct ConvertElement<T, ValueType::stlPair> { void writeStruc(const T& value, XmlElement& output) const { @@ -169,7 +170,7 @@ struct ConvertElement<T, ValueType::STL_PAIR> //partial specialization: not a pure structured type, try text conversion (thereby respect user specializations of writeText()/readText()) template <class T> -struct ConvertElement<T, ValueType::OTHER> +struct ConvertElement<T, ValueType::other> { void writeStruc(const T& value, XmlElement& output) const { diff --git a/zenXml/zenxml/cvrt_text.h b/zenXml/zenxml/cvrt_text.h index 058ffa30..c06a62e0 100644 --- a/zenXml/zenxml/cvrt_text.h +++ b/zenXml/zenxml/cvrt_text.h @@ -118,22 +118,22 @@ public: //Conversion from arbitrary types to text (for use with XML elements and attributes) -enum TextType +enum class TextType { - TEXT_TYPE_BOOL, - TEXT_TYPE_NUMBER, - TEXT_TYPE_CHRONO, - TEXT_TYPE_STRING, - TEXT_TYPE_OTHER, + boolean, + number, + chrono, + string, + other, }; template <class T> struct GetTextType : std::integral_constant<TextType, - std::is_same_v<T, bool> ? TEXT_TYPE_BOOL : - IsStringLikeV<T> ? TEXT_TYPE_STRING : //string before number to correctly handle char/wchar_t -> this was an issue with Loki only! - IsArithmeticV<T> ? TEXT_TYPE_NUMBER : // - IsChronoDuration<T>::value ? TEXT_TYPE_CHRONO : - TEXT_TYPE_OTHER> {}; + std::is_same_v<T, bool> ? TextType::boolean : + IsStringLikeV<T> ? TextType::string : //string before number to correctly handle char/wchar_t -> this was an issue with Loki only! + IsArithmeticV<T> ? TextType::number : // + IsChronoDuration<T>::value ? TextType::chrono : + TextType::other> {}; //###################################################################################### @@ -148,7 +148,7 @@ struct ConvertText; //partial specialization: type bool template <class T> -struct ConvertText<T, TEXT_TYPE_BOOL> +struct ConvertText<T, TextType::boolean> { void writeText(bool value, std::string& output) const { @@ -169,7 +169,7 @@ struct ConvertText<T, TEXT_TYPE_BOOL> //partial specialization: handle conversion for all built-in arithmetic types! template <class T> -struct ConvertText<T, TEXT_TYPE_NUMBER> +struct ConvertText<T, TextType::number> { void writeText(const T& value, std::string& output) const { @@ -183,7 +183,7 @@ struct ConvertText<T, TEXT_TYPE_NUMBER> }; template <class T> -struct ConvertText<T, TEXT_TYPE_CHRONO> +struct ConvertText<T, TextType::chrono> { void writeText(const T& value, std::string& output) const { @@ -198,7 +198,7 @@ struct ConvertText<T, TEXT_TYPE_CHRONO> //partial specialization: handle conversion for all string-like types! template <class T> -struct ConvertText<T, TEXT_TYPE_STRING> +struct ConvertText<T, TextType::string> { void writeText(const T& value, std::string& output) const { @@ -214,7 +214,7 @@ struct ConvertText<T, TEXT_TYPE_STRING> //partial specialization: unknown type template <class T> -struct ConvertText<T, TEXT_TYPE_OTHER> +struct ConvertText<T, TextType::other> { //########################################################################################################################################### static_assert(sizeof(T) == -1); diff --git a/zenXml/zenxml/dom.h b/zenXml/zenxml/dom.h index e77509bf..8d5bc0f5 100644 --- a/zenXml/zenxml/dom.h +++ b/zenXml/zenxml/dom.h @@ -24,8 +24,7 @@ public: XmlElement() {} //Construct an empty XML element - template <class String> - explicit XmlElement(const String& name, XmlElement* parent = nullptr) : name_(utfTo<std::string>(name)), parent_(parent) {} + explicit XmlElement(std::string name, XmlElement* parent = nullptr) : name_(std::move(name)), parent_(parent) {} ///Retrieve the name of this XML element. /** @@ -52,52 +51,46 @@ public: ///Retrieve an attribute by name. /** - \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \tparam T String-convertible user data type: e.g. any string class, all built-in arithmetic numbers \param name The name of the attribute to retrieve. \param value The value of the attribute converted to T. \return "true" if value was retrieved successfully. */ - template <class String, class T> - bool getAttribute(const String& name, T& value) const + template <class T> + bool getAttribute(const std::string& name, T& value) const { - auto it = attributesSorted_.find(utfTo<std::string>(name)); + auto it = attributesSorted_.find(name); return it == attributesSorted_.end() ? false : readText(it->second->value, value); } + bool hasAttribute(const std::string& name) const { return attributesSorted_.contains(name); } + ///Create or update an XML attribute. /** - \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \tparam T String-convertible user data type: e.g. any string-like type, all built-in arithmetic numbers \param name The name of the attribute to create or update. \param value The value to set. */ - template <class String, class T> - void setAttribute(const String& name, const T& value) + template <class T> + void setAttribute(std::string name, const T& value) { - std::string attrName = utfTo<std::string>(name); - std::string attrValue; writeText(value, attrValue); - auto it = attributesSorted_.find(attrName); + auto it = attributesSorted_.find(name); if (it != attributesSorted_.end()) it->second->value = std::move(attrValue); else { - auto itBack = attributes_.insert(attributes_.end(), {attrName, std::move(attrValue)}); - attributesSorted_.emplace(std::move(attrName), itBack); + auto itBack = attributes_.insert(attributes_.end(), {name, std::move(attrValue)}); + attributesSorted_.emplace(std::move(name), itBack); } } ///Remove the attribute with the given name. - /** - \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... - */ - template <class String> - void removeAttribute(const String& name) + void removeAttribute(const std::string& name) { - auto it = attributesSorted_.find(utfTo<std::string>(name)); + auto it = attributesSorted_.find(name); if (it != attributesSorted_.end()) { attributes_.erase(it->second); @@ -107,42 +100,36 @@ public: ///Create a new child element and return a reference to it. /** - \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \param name The name of the child element to be created. */ - template <class String> - XmlElement& addChild(const String& name) + XmlElement& addChild(std::string name) { - std::string elemName = utfTo<std::string>(name); - childElements_.emplace_back(elemName, this); + childElements_.emplace_back(name, this); XmlElement& newElement = childElements_.back(); - childElementsSorted_.emplace(std::move(elemName), &newElement); + childElementsSorted_.emplace(std::move(name), &newElement); return newElement; } ///Retrieve a child element with the given name. /** - \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \param name The name of the child element to be retrieved. \return A pointer to the child element or nullptr if none was found. */ - template <class String> - const XmlElement* getChild(const String& name) const + const XmlElement* getChild(const std::string& name) const { - auto it = childElementsSorted_.find(utfTo<std::string>(name)); + auto it = childElementsSorted_.find(name); return it == childElementsSorted_.end() ? nullptr : it->second; } ///\sa getChild - template <class String> - XmlElement* getChild(const String& name) + XmlElement* getChild(const std::string& name) { return const_cast<XmlElement*>(static_cast<const XmlElement*>(this)->getChild(name)); } - template < class IterTy, //underlying iterator type - class T, //target object type - class AccessPolicy > //access policy: see AccessPtrMap + template <class IterTy, //underlying iterator type + class T, //target object type + class AccessPolicy> //access policy: see AccessPtrMap class PtrIter : private AccessPolicy //get rid of shared_ptr indirection { public: @@ -175,19 +162,17 @@ public: ///Access all child elements with the given name via STL iterators. /** \code - auto iterPair = elem.getChildren("Item"); + auto itPair = elem.getChildren("Item"); std::for_each(iterPair.first, iterPair.second, [](const XmlElement& child) { ... }); \endcode \param name The name of the child elements to be retrieved. \return A pair of STL begin/end iterators to access the child elements sequentially. */ - template <class String> - std::pair<ChildIterConst2, ChildIterConst2> getChildren(const String& name) const { return childElementsSorted_.equal_range(utfTo<std::string>(name)); } + std::pair<ChildIterConst2, ChildIterConst2> getChildren(const std::string& name) const { return childElementsSorted_.equal_range(name); } ///\sa getChildren - template <class String> - std::pair<ChildIter2, ChildIter2> getChildren(const String& name) { return childElementsSorted_.equal_range(utfTo<std::string>(name)); } + std::pair<ChildIter2, ChildIter2> getChildren(const std::string& name) { return childElementsSorted_.equal_range(name); } struct AccessListElement { @@ -201,8 +186,8 @@ public: ///Access all child elements sequentially via STL iterators. /** \code - auto iterPair = elem.getChildren(); - std::for_each(iterPair.first, iterPair.second, + auto itPair = elem.getChildren(); + std::for_each(itPair.first, itPair.second, [](const XmlElement& child) { ... }); \endcode \return A pair of STL begin/end iterators to access all child elements sequentially. @@ -227,8 +212,8 @@ public: /* -> disabled documentation extraction \brief Get all attributes associated with the element. \code - auto iterPair = elem.getAttributes(); - for (auto it = iterPair.first; it != iterPair.second; ++it) + auto itPair = elem.getAttributes(); + for (auto it = itPair.first; it != itPair.second; ++it) std::cout << "name: " << it->name << " value: " << it->value << '\n'; \endcode \return A pair of STL begin/end iterators to access all attributes sequentially as a list of name/value pairs of std::string. */ @@ -286,11 +271,9 @@ public: //Setup an empty XML document /** - \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \param rootName The name of the XML document's root element. */ - template <class String> - XmlDoc(String rootName) : root_(rootName) {} + explicit XmlDoc(std::string rootName) : root_(std::move(rootName)) {} ///Get a const reference to the document's root element. const XmlElement& root() const { return root_; } @@ -334,7 +317,6 @@ private: XmlElement root_{"Root"}; }; - } #endif //DOM_H_82085720723894567204564256 diff --git a/zenXml/zenxml/parser.h b/zenXml/zenxml/parser.h index a4800ab3..14ccfd60 100644 --- a/zenXml/zenxml/parser.h +++ b/zenXml/zenxml/parser.h @@ -206,13 +206,13 @@ void serialize(const XmlElement& element, std::string& stream, for (auto it = attr.first; it != attr.second; ++it) stream += ' ' + normalizeName(it->name) + "=\"" + normalizeAttribValue(it->value) + '"'; - auto iterPair = element.getChildren(); - if (iterPair.first != iterPair.second) //structured element + auto itPair = element.getChildren(); + if (itPair.first != itPair.second) //structured element { //no support for mixed-mode content stream += '>' + lineBreak; - std::for_each(iterPair.first, iterPair.second, + std::for_each(itPair.first, itPair.second, [&](const XmlElement& el) { serialize(el, stream, lineBreak, indent, indentLevel + 1); }); for (size_t i = 0; i < indentLevel; ++i) diff --git a/zenXml/zenxml/xml.h b/zenXml/zenxml/xml.h index ffd00ea0..7e50221a 100644 --- a/zenXml/zenxml/xml.h +++ b/zenXml/zenxml/xml.h @@ -126,25 +126,28 @@ public: </Root> \endverbatim */ - XmlOut(XmlDoc& doc) : ref_(&doc.root()) {} - ///Construct an output proxy for a single XML element + explicit XmlOut(XmlDoc& doc) : ref_(&doc.root()) {} + + ///Retrieve a handle to an XML child element for writing /** - \sa XmlOut(XmlDoc& doc) + The child element will be created if it is not yet existing. + \param name The name of the child element */ - XmlOut(XmlElement& element) : ref_(&element) {} + XmlOut operator[](std::string name) const + { + XmlElement* child = ref_->getChild(name); + return XmlOut(child ? *child : ref_->addChild(std::move(name))); + } ///Retrieve a handle to an XML child element for writing /** - The child element will be created if it is not yet existing. + The child element will be added, allowing for multiple elements with the same name. \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \param name The name of the child element */ - template <class String> - XmlOut operator[](const String& name) const + XmlOut addChild(std::string name) const { - const std::string utf8name = utfTo<std::string>(name); - XmlElement* child = ref_->getChild(utf8name); - return child ? *child : ref_->addChild(utf8name); + return XmlOut(ref_->addChild(std::move(name))); } ///Write user data to the underlying XML element @@ -176,17 +179,19 @@ public: </Root> \endverbatim - \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \tparam T String-convertible user data type: e.g. any string-like type, all built-in arithmetic numbers \sa XmlElement::setAttribute() */ - template <class String, class T> - void attribute(const String& name, const T& value) { ref_->setAttribute(name, value); } - - ///Return a reference to the underlying Xml element - XmlElement& ref() { return *ref_; } + template <class T> + void attribute(std::string name, const T& value) { ref_->setAttribute(std::move(name), value); } private: + ///Construct an output proxy for a single XML element + /** + \sa XmlOut(XmlDoc& doc) + */ + explicit XmlOut(XmlElement& element) : ref_(&element) {} + XmlElement* ref_; //always bound! }; @@ -208,37 +213,28 @@ public: in["elem3"](value3); // \endcode */ - XmlIn(const XmlDoc& doc) { refList_.push_back(&doc.root()); } - ///Construct an input proxy for a single XML element, may be nullptr - /** - \sa XmlIn(const XmlDoc& doc) - */ - XmlIn(const XmlElement* element) { refList_.push_back(element); } - ///Construct an input proxy for a single XML element - /** - \sa XmlIn(const XmlDoc& doc) - */ - XmlIn(const XmlElement& element) { refList_.push_back(&element); } + explicit XmlIn(const XmlDoc& doc) : nodeNameFormatted_('<' + doc.root().getName() + '>') + { + refList_.push_back(&doc.root()); + } ///Retrieve a handle to an XML child element for reading /** It is \b not an error if the child element does not exist, but only later if a conversion to user data is attempted. - \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \param name The name of the child element */ - template <class String> - XmlIn operator[](const String& name) const + XmlIn operator[](const std::string& name) const { std::vector<const XmlElement*> childList; - if (refIndex_ < refList_.size()) + if (const XmlElement* elem = get()) { - auto iterPair = refList_[refIndex_]->getChildren(name); - std::for_each(iterPair.first, iterPair.second, - [&](const XmlElement& child) { childList.push_back(&child); }); + auto itPair = elem->getChildren(name); + std::for_each(itPair.first, itPair.second, [&](const XmlElement& child) + { childList.push_back(&child); }); } - return XmlIn(childList, childList.empty() ? getChildNameFormatted(name) : std::string(), log_); + return XmlIn(childList, getChildNameFormatted(name), log_); } ///Refer to next sibling element with the same name @@ -264,6 +260,18 @@ public: */ void next() { ++refIndex_; } + ///Test whether the underlying XML element exists + /** + \code + XmlIn in(doc); + XmlIn child = in["elem1"]; + if (child) + ... + \endcode + Use member pointer as implicit conversion to bool (C++ Templates - Vandevoorde/Josuttis; chapter 20) + */ + explicit operator bool() const { return get() != nullptr; } + ///Read user data from the underlying XML element /** This conversion requires a specialization of zen::readText() or zen::readStruc() for type T. @@ -273,18 +281,25 @@ public: template <class T> bool operator()(T& value) const { - if (refIndex_ < refList_.size()) + if (const XmlElement* elem = get()) { - const bool success = readStruc(*refList_[refIndex_], value); - if (!success) - log_.ref().notifyConversionError(getNameFormatted()); - return success; + if (readStruc(*elem, value)) + return true; + + log_.ref().notifyConversionError(getNameFormatted()); } else - { log_.ref().notifyMissingElement(getNameFormatted()); - return false; - } + + return false; + } + + bool hasAttribute(const std::string& name) const + { + if (const XmlElement* elem = get()) + if (elem->hasAttribute(name)) + return true; + return false; } ///Read user data from an XML attribute @@ -305,37 +320,21 @@ public: \returns "true" if the attribute was found and the conversion to the output value was successful. \sa XmlElement::getAttribute() */ - template <class String, class T> - bool attribute(const String& name, T& value) const + template <class T> + bool attribute(const std::string& name, T& value) const { - if (refIndex_ < refList_.size()) + if (const XmlElement* elem = get()) { - const bool success = refList_[refIndex_]->getAttribute(name, value); - if (!success) - log_.ref().notifyMissingAttribute(getNameFormatted(), utfTo<std::string>(name)); - return success; + if (elem->getAttribute(name, value)) + return true; + + log_.ref().notifyMissingAttribute(getNameFormatted(), name); } else - { log_.ref().notifyMissingElement(getNameFormatted()); - return false; - } - } - ///Return a pointer to the underlying Xml element, may be nullptr - const XmlElement* get() const { return refIndex_ < refList_.size() ? refList_[refIndex_] : nullptr; } - - ///Test whether the underlying XML element exists - /** - \code - XmlIn in(doc); - XmlIn child = in["elem1"]; - if (child) - ... - \endcode - Use member pointer as implicit conversion to bool (C++ Templates - Vandevoorde/Josuttis; chapter 20) - */ - explicit operator bool() const { return get() != nullptr; } + return false; + } ///Notifies errors while mapping the XML to user data /** @@ -357,56 +356,47 @@ public: However be aware that the chain of connected proxy instances will be broken once you call XmlIn::get() to retrieve the underlying pointer. Errors that occur when working with this pointer are not logged by the original set of related instances. */ - bool haveErrors() const { return !log_.ref().elementList().empty(); } ///Get a list of XML element and attribute names which failed to convert to user data. /** - \tparam String Arbitrary string class: e.g. std::string, std::wstring, wxString, MyStringClass, ... \returns A list of XML element and attribute names, empty list if no errors occured. */ - template <class String> - std::vector<String> getErrorsAs() const + std::vector<std::wstring> getErrors() const { - std::vector<String> output; + std::vector<std::wstring> output; for (const std::string& str : log_.ref().elementList()) - output.push_back(utfTo<String>(str)); + output.push_back(utfTo<std::wstring>(str)); return output; } private: - XmlIn(const std::vector<const XmlElement*>& siblingList, const std::string& elementNameFmt, const SharedRef<ErrorLog>& sharedlog) : - refList_(siblingList), formattedName_(elementNameFmt), log_(sharedlog) - { assert((!siblingList.empty() && elementNameFmt.empty()) || (siblingList.empty() && !elementNameFmt.empty())); } + XmlIn(const std::vector<const XmlElement*>& siblingList, + const std::string& nodeNameFormatted, + const SharedRef<ErrorLog>& sharedlog) : refList_(siblingList), nodeNameFormatted_(nodeNameFormatted), log_(sharedlog) {} - static std::string getNameFormatted(const XmlElement& elem) //"<Root> <Level1> <Level2>" - { - return (elem.parent() ? getNameFormatted(*elem.parent()) + ' ' : std::string()) + '<' + elem.getName() + '>'; - } + ///Return a pointer to the underlying Xml element, may be nullptr + const XmlElement* get() const { return refIndex_ < refList_.size() ? refList_[refIndex_] : nullptr; } - std::string getNameFormatted() const + std::string getNameFormatted() const //"<Root> <Level1> <Level2>" { - if (refIndex_ < refList_.size()) - { - assert(formattedName_.empty()); - return getNameFormatted(*refList_[refIndex_]); - } + if (refIndex_ == 0 && refList_.size() <= 1) + return nodeNameFormatted_; else - return formattedName_; + return nodeNameFormatted_ + '[' + numberTo<std::string>(refIndex_ + 1) + ']'; } std::string getChildNameFormatted(const std::string& childName) const { - std::string parentName = getNameFormatted(); - return (parentName.empty() ? std::string() : (parentName + ' ')) + '<' + childName + '>'; + return getNameFormatted() + " <" + childName + '>'; } class ErrorLog { public: - void notifyConversionError (const std::string& displayName) { insert(displayName); } - void notifyMissingElement (const std::string& displayName) { insert(displayName); } + void notifyConversionError (const std::string& displayName) { insert(displayName); } + void notifyMissingElement (const std::string& displayName) { insert(displayName); } void notifyMissingAttribute(const std::string& displayName, const std::string& attribName) { insert(displayName + " @" + attribName); } const std::vector<std::string>& elementList() const { return failedElements; } @@ -424,7 +414,7 @@ private: std::vector<const XmlElement*> refList_; //all sibling elements with same name (all pointers bound!) size_t refIndex_ = 0; //this sibling's index in refList_ - std::string formattedName_; //contains full and formatted element name if (and only if) refList_ is empty + std::string nodeNameFormatted_; mutable SharedRef<ErrorLog> log_ = makeSharedRef<ErrorLog>(); }; @@ -438,10 +428,11 @@ private: inline void checkXmlMappingErrors(const XmlIn& xmlInput, const Zstring& filePath) //throw FileError { - if (xmlInput.haveErrors()) + if (const std::vector<std::wstring>& errors = xmlInput.getErrors(); + !errors.empty()) { std::wstring msg = _("The following XML elements could not be read:") + L'\n'; - for (const std::wstring& elem : xmlInput.getErrorsAs<std::wstring>()) + for (const std::wstring& elem : errors) msg += L'\n' + elem; throw FileError(replaceCpy(_("Configuration file %x is incomplete. The missing elements will be set to their default values."), L"%x", fmtPath(filePath)) + L"\n\n" + msg); |