summaryrefslogtreecommitdiff
path: root/zenXml
diff options
context:
space:
mode:
authorB. Stack <bgstack15@gmail.com>2021-04-05 15:59:11 +0000
committerB. Stack <bgstack15@gmail.com>2021-04-05 15:59:11 +0000
commit8d28254d708c88ae4aaebbc82cbb6c91726aa390 (patch)
treedafb5e266c513a5ed9863401e62d246742861e0c /zenXml
parentMerge branch '11.7' into 'master' (diff)
parentadd upstream 11.9 (diff)
downloadFreeFileSync-8d28254d708c88ae4aaebbc82cbb6c91726aa390.tar.gz
FreeFileSync-8d28254d708c88ae4aaebbc82cbb6c91726aa390.tar.bz2
FreeFileSync-8d28254d708c88ae4aaebbc82cbb6c91726aa390.zip
Merge branch '11.9' into 'master'11.9
add upstream 11.9 See merge request opensource-tracking/FreeFileSync!32
Diffstat (limited to 'zenXml')
-rw-r--r--zenXml/zenxml/cvrt_struc.h35
-rw-r--r--zenXml/zenxml/cvrt_text.h32
-rw-r--r--zenXml/zenxml/dom.h78
-rw-r--r--zenXml/zenxml/parser.h6
-rw-r--r--zenXml/zenxml/xml.h181
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);
bgstack15