summaryrefslogtreecommitdiff
path: root/slicer/xml
diff options
context:
space:
mode:
Diffstat (limited to 'slicer/xml')
-rw-r--r--slicer/xml/serializer.cpp724
-rw-r--r--slicer/xml/serializer.h48
-rw-r--r--slicer/xml/testSpecifics.cpp82
-rw-r--r--slicer/xml/xmlExceptions.ice4
4 files changed, 460 insertions, 398 deletions
diff --git a/slicer/xml/serializer.cpp b/slicer/xml/serializer.cpp
index 96c1a9f..8e351b6 100644
--- a/slicer/xml/serializer.cpp
+++ b/slicer/xml/serializer.cpp
@@ -1,5 +1,5 @@
#include "serializer.h"
-#include <boost/lexical_cast.hpp>
+#include <charconv>
#include <compileTimeFormatter.h>
#include <functional>
#pragma GCC diagnostic push
@@ -10,16 +10,16 @@
#endif
#include <glibmm/ustring.h>
#include <libxml++/attribute.h>
+#include <libxml++/document.h>
#include <libxml++/nodes/contentnode.h>
#include <libxml++/nodes/element.h>
#include <libxml++/nodes/node.h>
+#include <libxml++/parsers/domparser.h>
#pragma GCC diagnostic pop
#include <Ice/Config.h>
#include <boost/numeric/conversion/cast.hpp>
#include <factory.h>
#include <lazyPointer.h>
-#include <libxml++/document.h>
-#include <libxml++/parsers/domparser.h>
#include <list>
#include <memory>
#include <optional>
@@ -37,327 +37,365 @@ NAMEDFACTORY("application/xml", Slicer::XmlStreamSerializer, Slicer::StreamSeria
NAMEDFACTORY("application/xml", Slicer::XmlStreamDeserializer, Slicer::StreamDeserializerFactory)
namespace Slicer {
- constexpr std::string_view md_attribute {"xml:attribute"};
- constexpr std::string_view md_text {"xml:text"};
- constexpr std::string_view md_bare {"xml:bare"};
- constexpr std::string_view md_attributes {"xml:attributes"};
- constexpr std::string_view md_elements {"xml:elements"};
- constexpr std::string_view keyName {"key"};
- constexpr std::string_view valueName {"value"};
+ namespace {
+ constexpr std::string_view md_attribute {"xml:attribute"};
+ constexpr std::string_view md_text {"xml:text"};
+ constexpr std::string_view md_bare {"xml:bare"};
+ constexpr std::string_view md_attributes {"xml:attributes"};
+ constexpr std::string_view md_elements {"xml:elements"};
+ constexpr std::string_view keyName {"key"};
+ constexpr std::string_view valueName {"value"};
- constexpr auto defaultElementCreator = [](auto && element, auto && name) {
- return element->add_child_element(name);
- };
+ using CurrentElementCreator = ::AdHoc::LazyPointer<xmlpp::Element, xmlpp::Element *>;
+ using ElementCreator = std::function<xmlpp::Element *(xmlpp::Element *, const Glib::ustring &)>;
- static const Glib::ustring TrueText("true");
- static const Glib::ustring FalseText("false");
+ constexpr auto defaultElementCreator = [](auto && element, auto && name) {
+ return element->add_child_element(name);
+ };
- class XmlValueSource : public ValueSource {
- public:
- explicit XmlValueSource(Glib::ustring s) : value(std::move(s)) { }
+ const Glib::ustring TrueText("true");
+ const Glib::ustring FalseText("false");
- void
- set(bool & v) const override
- {
- if (value == TrueText) {
- v = true;
- return;
+ class XmlValueSource : public ValueSource {
+ public:
+ explicit XmlValueSource() = default;
+
+ explicit XmlValueSource(Glib::ustring s) : value(std::move(s)) { }
+
+ explicit XmlValueSource(const xmlpp::ContentNode * c) : value(c->get_content()) { }
+
+ explicit XmlValueSource(const xmlpp::Attribute * a) : value(a->get_value()) { }
+
+ void
+ set(bool & v) const override
+ {
+ if (value == TrueText) {
+ v = true;
+ return;
+ }
+ if (value == FalseText) {
+ v = false;
+ return;
+ }
+ throw BadBooleanValue(value);
}
- if (value == FalseText) {
- v = false;
- return;
+
+ void
+ set(Ice::Byte & v) const override
+ {
+ from_chars(v);
}
- throw BadBooleanValue(value);
- }
- void
- set(Ice::Byte & v) const override
- {
- v = boost::numeric_cast<Ice::Byte>(boost::lexical_cast<int>(value));
- }
+ void
+ set(Ice::Short & v) const override
+ {
+ from_chars(v);
+ }
- void
- set(Ice::Short & v) const override
- {
- v = boost::lexical_cast<Ice::Short>(value);
- }
+ void
+ set(Ice::Int & v) const override
+ {
+ from_chars(v);
+ }
- void
- set(Ice::Int & v) const override
- {
- v = boost::lexical_cast<Ice::Int>(value);
- }
+ void
+ set(Ice::Long & v) const override
+ {
+ from_chars(v);
+ }
- void
- set(Ice::Long & v) const override
- {
- v = boost::lexical_cast<Ice::Long>(value);
- }
+ void
+ set(Ice::Float & v) const override
+ {
+ from_chars(v);
+ }
- void
- set(Ice::Float & v) const override
- {
- v = boost::lexical_cast<Ice::Float>(value);
- }
+ void
+ set(Ice::Double & v) const override
+ {
+ from_chars(v);
+ }
- void
- set(Ice::Double & v) const override
- {
- v = boost::lexical_cast<Ice::Double>(value);
- }
+ void
+ set(std::string & v) const override
+ {
+ v = value.raw();
+ }
- void
- set(std::string & v) const override
- {
- v = value.raw();
- }
+ private:
+ template<typename T>
+ void
+ from_chars(T & v) const
+ {
+ std::string_view raw {value.raw()};
+ if (std::from_chars(raw.begin(), raw.end(), v).ec != std::errc {}) {
+ throw BadNumericValue(value);
+ }
+ }
- private:
- const Glib::ustring value;
- };
+ const Glib::ustring value;
+ };
- class XmlContentValueSource : public XmlValueSource {
- public:
- explicit XmlContentValueSource() : XmlValueSource(Glib::ustring()) { }
- explicit XmlContentValueSource(const xmlpp::ContentNode * c) : XmlValueSource(c->get_content()) { }
- };
+ class XmlValueTarget : public ValueTarget {
+ public:
+ using ApplyFunction = std::function<void(const Glib::ustring &)>;
- class XmlAttributeValueSource : public XmlValueSource {
- public:
- explicit XmlAttributeValueSource(const xmlpp::Attribute * a) : XmlValueSource(a->get_value()) { }
- };
+ explicit XmlValueTarget(ApplyFunction a) : apply(std::move(a)) { }
- class XmlValueTarget : public ValueTarget {
- public:
- explicit XmlValueTarget(std::function<void(const Glib::ustring &)> a) : apply(std::move(a)) { }
+ explicit XmlValueTarget(xmlpp::Element * p, const std::string & n) :
+ apply([p, n](auto && PH1) {
+ p->set_attribute(n, PH1);
+ })
+ {
+ }
- void
- get(const bool & value) const override
- {
- if (value) {
- apply(TrueText);
+ explicit XmlValueTarget(xmlpp::Element * p) :
+ apply([p](auto && PH1) {
+ p->set_first_child_text(PH1);
+ })
+ {
}
- else {
- apply(FalseText);
+
+ explicit XmlValueTarget(const CurrentElementCreator & cec) :
+ apply([&](auto && PH1) {
+ cec->set_first_child_text(PH1);
+ })
+ {
}
- }
- void
- get(const Ice::Byte & value) const override
- {
- apply(boost::lexical_cast<Glib::ustring, int>(value));
- }
+ void
+ get(const bool & value) const override
+ {
+ if (value) {
+ apply(TrueText);
+ }
+ else {
+ apply(FalseText);
+ }
+ }
- void
- get(const Ice::Short & value) const override
- {
- apply(boost::lexical_cast<Glib::ustring>(value));
- }
+ void
+ get(const Ice::Byte & value) const override
+ {
+ apply(Glib::ustring::format(value));
+ }
+
+ void
+ get(const Ice::Short & value) const override
+ {
+ apply(Glib::ustring::format(value));
+ }
+
+ void
+ get(const Ice::Int & value) const override
+ {
+ apply(Glib::ustring::format(value));
+ }
+
+ void
+ get(const Ice::Long & value) const override
+ {
+ apply(Glib::ustring::format(value));
+ }
+
+ void
+ get(const Ice::Float & value) const override
+ {
+ apply(Glib::ustring::format(value));
+ }
+
+ void
+ get(const Ice::Double & value) const override
+ {
+ apply(Glib::ustring::format(value));
+ }
+
+ void
+ get(const std::string & value) const override
+ {
+ apply(value);
+ }
+
+ private:
+ const ApplyFunction apply;
+ };
+
+ void DocumentTreeIterate(const xmlpp::Node * node, ModelPartParam mp);
+ void DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartParam mp, const Metadata & md);
+ void DocumentTreeIterate(const xmlpp::Document * doc, ModelPartParam mp);
+ void DocumentTreeIterateDictAttrs(const xmlpp::Element::const_AttributeList & attrs, ModelPartParam dict);
+ void DocumentTreeIterateDictElements(const xmlpp::Element * parent, ModelPartParam dict);
void
- get(const Ice::Int & value) const override
+ DocumentTreeIterateDictAttrs(const xmlpp::Element::const_AttributeList & attrs, ModelPartParam dict)
{
- apply(boost::lexical_cast<Glib::ustring>(value));
+ for (const auto & attr : attrs) {
+ dict->OnAnonChild([&attr](auto && emp, auto &&) {
+ emp->Create();
+ emp->OnChild(
+ [&attr](auto && child, auto &&) {
+ child->SetValue(XmlValueSource(attr->get_name()));
+ child->Complete();
+ },
+ keyName);
+ emp->OnChild(
+ [&attr](auto && value, auto &&) {
+ value->SetValue(XmlValueSource(attr->get_value()));
+ value->Complete();
+ },
+ valueName);
+ emp->Complete();
+ });
+ }
}
void
- get(const Ice::Long & value) const override
+ DocumentTreeIterateDictElements(const xmlpp::Element * element, ModelPartParam dict)
{
- apply(boost::lexical_cast<Glib::ustring>(value));
+ auto node = element->get_first_child();
+ while (node) {
+ if (auto childElement = dynamic_cast<const xmlpp::Element *>(node)) {
+ dict->OnAnonChild([childElement](auto && emp, auto &&) {
+ emp->Create();
+ emp->OnChild(
+ [childElement](auto && child, auto &&) {
+ child->SetValue(XmlValueSource(childElement->get_name()));
+ child->Complete();
+ },
+ keyName);
+ emp->OnChild(
+ [childElement](auto && value, auto && md) {
+ DocumentTreeIterateElement(childElement, value, md);
+ },
+ valueName);
+ emp->Complete();
+ });
+ }
+ node = node->get_next_sibling();
+ }
}
void
- get(const Ice::Float & value) const override
+ DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartParam smp, const Metadata & md)
{
- apply(boost::lexical_cast<Glib::ustring>(value));
+ auto oec = [&md, element](const auto & lmp) {
+ lmp->Create();
+ if (md.flagSet(md_attributes)) {
+ auto attrs(element->get_attributes());
+ if (!attrs.empty()) {
+ DocumentTreeIterateDictAttrs(attrs, lmp);
+ }
+ }
+ else if (md.flagSet(md_elements)) {
+ DocumentTreeIterateDictElements(element, lmp);
+ }
+ else {
+ auto attrs(element->get_attributes());
+ if (!attrs.empty()) {
+ DocumentTreeIterate(attrs.front(), lmp);
+ }
+ auto firstChild = element->get_first_child();
+ if (firstChild) {
+ DocumentTreeIterate(firstChild, lmp);
+ }
+ else {
+ lmp->SetValue(XmlValueSource());
+ }
+ }
+ lmp->Complete();
+ };
+ if (auto typeIdPropName = smp->GetTypeIdProperty()) {
+ if (auto typeAttr = element->get_attribute(*typeIdPropName)) {
+ return smp->OnSubclass(oec, typeAttr->get_value());
+ }
+ }
+ oec(smp);
}
void
- get(const Ice::Double & value) const override
+ DocumentTreeIterate(const xmlpp::Node * node, ModelPartParam mp)
{
- apply(boost::lexical_cast<Glib::ustring>(value));
+ while (node) {
+ if (auto element = dynamic_cast<const xmlpp::Element *>(node)) {
+ mp->OnChild(
+ [element](auto && smp, auto && md) {
+ if (md.flagSet(md_bare)) {
+ smp->OnAnonChild([element](auto && bmp, auto && bmd) {
+ DocumentTreeIterateElement(element, bmp, bmd);
+ });
+ return;
+ }
+ DocumentTreeIterateElement(element, smp, md);
+ },
+ element->get_name().raw(),
+ [](const auto & h) {
+ return h->GetMetadata().flagNotSet(md_attribute);
+ });
+ }
+ else if (auto attribute = dynamic_cast<const xmlpp::Attribute *>(node)) {
+ mp->OnChild(
+ [attribute](auto && smp, auto &&) {
+ smp->Create();
+ smp->SetValue(XmlValueSource(attribute));
+ smp->Complete();
+ },
+ attribute->get_name().raw(),
+ [](const auto & h) {
+ return h->GetMetadata().flagSet(md_attribute);
+ });
+ }
+ else if (auto content = dynamic_cast<const xmlpp::ContentNode *>(node)) {
+ bool bare = false;
+ if (!content->is_white_space()) {
+ bare = (mp->OnAnonChild(
+ [content](auto && smp, auto &&) {
+ smp->SetValue(XmlValueSource(content));
+ },
+ [](const auto & h) {
+ return h->GetMetadata().flagSet(md_text);
+ }));
+ }
+ if (!bare) {
+ mp->SetValue(XmlValueSource(content));
+ }
+ }
+ node = node->get_next_sibling();
+ }
}
void
- get(const std::string & value) const override
+ DocumentTreeIterate(const xmlpp::Document * doc, ModelPartParam mp)
{
- apply(value);
+ DocumentTreeIterate(doc->get_root_node(), mp);
}
- private:
- const std::function<void(const Glib::ustring &)> apply;
- };
-
- class XmlAttributeValueTarget : public XmlValueTarget {
- public:
- explicit XmlAttributeValueTarget(xmlpp::Element * p, const std::string & n) :
- XmlValueTarget([p, n](auto && PH1) {
- p->set_attribute(n, PH1);
- })
- {
- }
- };
-
- class XmlContentValueTarget : public XmlValueTarget {
- public:
- explicit XmlContentValueTarget(xmlpp::Element * p) :
- XmlValueTarget([p](auto && PH1) {
- p->set_first_child_text(PH1);
- })
- {
- }
+ void ModelTreeIterate(xmlpp::Element *, const std::string &, ModelPartParam mp, const HookCommon * hp,
+ const ElementCreator &);
+ void ModelTreeIterateRoot(xmlpp::Document *, const std::string &, ModelPartParam mp);
+ void ModelTreeProcessElement(const CurrentElementCreator &, ModelPartParam mp, const ElementCreator &);
+ void ModelTreeIterateDictAttrs(xmlpp::Element * element, ModelPartParam dict);
+ void ModelTreeIterateDictElements(xmlpp::Element * element, ModelPartParam dict);
- explicit XmlContentValueTarget(const CurrentElementCreator & cec) :
- XmlValueTarget([&](auto && PH1) {
- cec->set_first_child_text(PH1);
- })
+ void
+ ModelTreeIterate(xmlpp::Element * n, const std::string & name, ModelPartParam mp, const HookCommon * hp,
+ const ElementCreator & ec)
{
- }
- };
-
- void
- XmlDeserializer::DocumentTreeIterateDictAttrs(
- const xmlpp::Element::const_AttributeList & attrs, const ModelPartPtr & dict)
- {
- for (const auto & attr : attrs) {
- auto emp = dict->GetAnonChild();
- emp->Create();
- auto key = emp->GetChild(keyName);
- auto value = emp->GetChild(valueName);
- key->SetValue(XmlValueSource(attr->get_name()));
- key->Complete();
- value->SetValue(XmlValueSource(attr->get_value()));
- value->Complete();
- emp->Complete();
- }
- }
-
- void
- XmlDeserializer::DocumentTreeIterateDictElements(const xmlpp::Element * element, const ModelPartPtr & dict)
- {
- auto node = element->get_first_child();
- while (node) {
- if (auto childElement = dynamic_cast<const xmlpp::Element *>(node)) {
- auto emp = dict->GetAnonChild();
- emp->Create();
- auto key = emp->GetChild(keyName);
- auto value = emp->GetChildRef(valueName);
- key->SetValue(XmlValueSource(childElement->get_name()));
- key->Complete();
- DocumentTreeIterateElement(childElement, value.Child(), value);
- emp->Complete();
- }
- node = node->get_next_sibling();
- }
- }
-
- void
- XmlDeserializer::DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartPtr smp, const ChildRef & smpr)
- {
- if (auto typeIdPropName = smp->GetTypeIdProperty()) {
- if (auto typeAttr = element->get_attribute(*typeIdPropName)) {
- smp = smp->GetSubclassModelPart(typeAttr->get_value());
- }
- }
- smp->Create();
- if (smpr.ChildMetaData().flagSet(md_attributes)) {
- auto attrs(element->get_attributes());
- if (!attrs.empty()) {
- DocumentTreeIterateDictAttrs(attrs, smp);
- }
- }
- else if (smpr.ChildMetaData().flagSet(md_elements)) {
- DocumentTreeIterateDictElements(element, smp);
- }
- else {
- auto attrs(element->get_attributes());
- if (!attrs.empty()) {
- DocumentTreeIterate(attrs.front(), smp);
- }
- auto firstChild = element->get_first_child();
- if (firstChild) {
- DocumentTreeIterate(firstChild, smp);
+ if (name.empty()) {
+ return;
}
- else {
- smp->SetValue(XmlContentValueSource());
+ if (hp && hp->GetMetadata().flagSet(md_attribute)) {
+ mp->GetValue(XmlValueTarget(n, name));
}
- }
- smp->Complete();
- }
-
- void
- XmlDeserializer::DocumentTreeIterate(const xmlpp::Node * node, const ModelPartPtr & mp)
- {
- while (node) {
- if (auto element = dynamic_cast<const xmlpp::Element *>(node)) {
- auto smpr = mp->GetChildRef(element->get_name().raw(), [](const auto & h) {
- return h->GetMetadata().flagNotSet(md_attribute);
- });
- if (smpr) {
- auto smp = smpr.Child();
- if (smpr.ChildMetaData().flagSet(md_bare)) {
- smp = smp->GetAnonChild();
- }
- if (smp) {
- DocumentTreeIterateElement(element, smp, smpr);
- }
- }
+ else if (hp && hp->GetMetadata().flagSet(md_text)) {
+ mp->GetValue(XmlValueTarget(n));
}
- else if (auto attribute = dynamic_cast<const xmlpp::Attribute *>(node)) {
- auto smp = mp->GetChild(attribute->get_name().raw(), [](const auto & h) {
- return h->GetMetadata().flagSet(md_attribute);
- });
- if (smp) {
- smp->Create();
- smp->SetValue(XmlAttributeValueSource(attribute));
- smp->Complete();
- }
+ else if (hp && hp->GetMetadata().flagSet(md_attributes)) {
+ ModelTreeIterateDictAttrs(n->add_child_element(name), mp);
}
- else if (auto content = dynamic_cast<const xmlpp::ContentNode *>(node)) {
- ModelPartPtr smp;
- if (!content->is_white_space()) {
- smp = mp->GetAnonChild([](const auto & h) {
- return h->GetMetadata().flagSet(md_text);
- });
- }
- if (smp) {
- smp->SetValue(XmlContentValueSource(content));
- }
- else {
- mp->SetValue(XmlContentValueSource(content));
- }
+ else if (hp && hp->GetMetadata().flagSet(md_elements)) {
+ ModelTreeIterateDictElements(n->add_child_element(name), mp);
}
- node = node->get_next_sibling();
- }
- }
-
- void
- XmlDeserializer::DocumentTreeIterate(const xmlpp::Document * doc, const ModelPartPtr & mp)
- {
- DocumentTreeIterate(doc->get_root_node(), mp);
- }
-
- void
- XmlSerializer::ModelTreeIterate(xmlpp::Element * n, const std::string & name, const ModelPartPtr & mp,
- const HookCommon * hp, const ElementCreator & ec)
- {
- if (name.empty()) {
- return;
- }
- if (hp && hp->GetMetadata().flagSet(md_attribute)) {
- mp->GetValue(XmlAttributeValueTarget(n, name));
- }
- else if (hp && hp->GetMetadata().flagSet(md_text)) {
- mp->GetValue(XmlContentValueTarget(n));
- }
- else if (hp && hp->GetMetadata().flagSet(md_attributes)) {
- ModelTreeIterateDictAttrs(n->add_child_element(name), mp);
- }
- else if (hp && hp->GetMetadata().flagSet(md_elements)) {
- ModelTreeIterateDictElements(n->add_child_element(name), mp);
- }
- else {
- if (hp && hp->GetMetadata().flagSet(md_bare)) {
+ else if (hp && hp->GetMetadata().flagSet(md_bare)) {
ModelTreeProcessElement(n, mp, [name](auto && PH1, auto &&) {
return PH1->add_child_element(name);
});
@@ -369,60 +407,81 @@ namespace Slicer {
ModelTreeProcessElement(cec, mp, defaultElementCreator);
}
}
- }
- void
- XmlSerializer::ModelTreeIterateDictAttrs(xmlpp::Element * element, const ModelPartPtr & dict)
- {
- dict->OnEachChild([element](const auto &, const auto & mp, const auto &) {
- if (mp->HasValue()) {
- mp->GetChild(keyName)->GetValue(XmlValueTarget([&mp, element](const auto & name) {
- mp->GetChild(valueName)->GetValue(XmlAttributeValueTarget(element, name));
- }));
- }
- });
- }
+ void
+ ModelTreeIterateDictAttrs(xmlpp::Element * element, ModelPartParam dict)
+ {
+ dict->OnEachChild([element](const auto &, const auto & mp, const auto &) {
+ if (mp->HasValue()) {
+ mp->OnChild(
+ [mp, element](auto && key, auto &&) {
+ key->GetValue(XmlValueTarget([mp, element](const auto & name) {
+ mp->OnChild(
+ [element, &name](auto && value, auto &&) {
+ value->GetValue(XmlValueTarget(element, name));
+ },
+ valueName);
+ }));
+ },
+ keyName);
+ }
+ });
+ }
- void
- XmlSerializer::ModelTreeIterateDictElements(xmlpp::Element * element, const ModelPartPtr & dict)
- {
- dict->OnEachChild([element](const auto &, const auto & mp, const auto &) {
- if (mp->HasValue()) {
- mp->GetChild(keyName)->GetValue(XmlValueTarget([&mp, element](const auto & name) {
- CurrentElementCreator cec([&element, &name]() {
- return element->add_child_element(name);
+ void
+ ModelTreeIterateDictElements(xmlpp::Element * element, ModelPartParam dict)
+ {
+ dict->OnEachChild([element](const auto &, const auto & mp, const auto &) {
+ if (mp->HasValue()) {
+ mp->OnChild(
+ [mp, element](auto && key, auto &&) {
+ key->GetValue(XmlValueTarget([mp, element](const auto & name) {
+ CurrentElementCreator cec([&element, &name]() {
+ return element->add_child_element(name);
+ });
+ mp->OnChild(
+ [&cec](auto && value, auto &&) {
+ ModelTreeProcessElement(cec, value, defaultElementCreator);
+ },
+ valueName);
+ }));
+ },
+ keyName);
+ }
+ });
+ }
+
+ void
+ ModelTreeProcessElement(const CurrentElementCreator & cec, ModelPartParam mp, const ElementCreator & ec)
+ {
+ if (mp->GetType() == ModelPartType::Simple) {
+ mp->GetValue(XmlValueTarget(cec));
+ }
+ else if (mp->HasValue()) {
+ auto oec = [element = cec.get(), &ec](const auto & lmp) {
+ lmp->OnEachChild([element, &ec](auto && PH1, auto && PH2, auto && PH3) {
+ return ModelTreeIterate(element, PH1, PH2, PH3, ec);
});
- ModelTreeProcessElement(cec, mp->GetChild(valueName), defaultElementCreator);
- }));
+ return element;
+ };
+ if (auto typeIdPropName = mp->GetTypeIdProperty()) {
+ if (auto typeId = mp->GetTypeId()) {
+ return mp->OnSubclass(
+ [oec, &typeIdPropName, &typeId](auto && smp) {
+ oec(smp)->set_attribute(*typeIdPropName, *typeId);
+ },
+ *typeId);
+ }
+ }
+ oec(mp);
}
- });
- }
-
- void
- XmlSerializer::ModelTreeProcessElement(
- const CurrentElementCreator & cec, ModelPartPtr mp, const ElementCreator & ec)
- {
- if (mp->GetType() == ModelPartType::Simple) {
- mp->GetValue(XmlContentValueTarget(cec));
- }
- else if (mp->HasValue()) {
- auto typeIdPropName = mp->GetTypeIdProperty();
- auto typeId = mp->GetTypeId();
- auto element = cec.get();
- if (typeId && typeIdPropName) {
- element->set_attribute(*typeIdPropName, *typeId);
- mp = mp->GetSubclassModelPart(*typeId);
- }
- mp->OnEachChild([element, ec](auto && PH1, auto && PH2, auto && PH3) {
- return XmlSerializer::ModelTreeIterate(element, PH1, PH2, PH3, ec);
- });
}
- }
- void
- XmlSerializer::ModelTreeIterateRoot(xmlpp::Document * doc, const std::string & name, const ModelPartPtr & mp)
- {
- ModelTreeProcessElement(doc->create_root_node(name), mp, defaultElementCreator);
+ void
+ ModelTreeIterateRoot(xmlpp::Document * doc, const std::string & name, ModelPartParam mp)
+ {
+ ModelTreeProcessElement(doc->create_root_node(name), mp, defaultElementCreator);
+ }
}
XmlStreamSerializer::XmlStreamSerializer(std::ostream & s) : strm(s) { }
@@ -430,7 +489,7 @@ namespace Slicer {
XmlStreamDeserializer::XmlStreamDeserializer(std::istream & s) : strm(s) { }
void
- XmlStreamDeserializer::Deserialize(ModelPartForRootPtr modelRoot)
+ XmlStreamDeserializer::Deserialize(ModelPartForRootParam modelRoot)
{
xmlpp::DomParser dom;
dom.parse_stream(strm);
@@ -439,7 +498,7 @@ namespace Slicer {
}
void
- XmlStreamSerializer::Serialize(ModelPartForRootPtr modelRoot)
+ XmlStreamSerializer::Serialize(ModelPartForRootParam modelRoot)
{
XmlDocumentSerializer::Serialize(modelRoot);
doc.write_to_stream(strm);
@@ -450,7 +509,7 @@ namespace Slicer {
XmlFileDeserializer::XmlFileDeserializer(std::filesystem::path p) : path(std::move(p)) { }
void
- XmlFileDeserializer::Deserialize(ModelPartForRootPtr modelRoot)
+ XmlFileDeserializer::Deserialize(ModelPartForRootParam modelRoot)
{
xmlpp::DomParser dom(path);
auto doc = dom.get_document();
@@ -460,23 +519,32 @@ namespace Slicer {
XmlDocumentDeserializer::XmlDocumentDeserializer(const xmlpp::Document * d) : doc(d) { }
void
- XmlDocumentDeserializer::Deserialize(ModelPartForRootPtr modelRoot)
+ XmlDocumentDeserializer::Deserialize(ModelPartForRootParam modelRoot)
{
DocumentTreeIterate(doc, modelRoot);
}
void
- XmlDocumentSerializer::Serialize(ModelPartForRootPtr modelRoot)
+ XmlDocumentSerializer::Serialize(ModelPartForRootParam modelRoot)
{
modelRoot->OnEachChild([this](auto && PH1, auto && PH2, auto &&) {
- return XmlSerializer::ModelTreeIterateRoot(&doc, PH1, PH2);
+ return ModelTreeIterateRoot(&doc, PH1, PH2);
});
}
AdHocFormatter(BadBooleanValueMsg, "Bad boolean value [%?]");
+
void
BadBooleanValue::ice_print(std::ostream & s) const
{
BadBooleanValueMsg::write(s, text);
}
+
+ AdHocFormatter(BadNumericValueMsg, "Bad numeric value [%?]");
+
+ void
+ BadNumericValue::ice_print(std::ostream & s) const
+ {
+ BadNumericValueMsg::write(s, text);
+ }
}
diff --git a/slicer/xml/serializer.h b/slicer/xml/serializer.h
index d07a77e..9c6e1ae 100644
--- a/slicer/xml/serializer.h
+++ b/slicer/xml/serializer.h
@@ -1,7 +1,6 @@
#ifndef SLICER_XML_H
#define SLICER_XML_H
-#include <lazyPointer.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wsign-conversion"
@@ -9,39 +8,22 @@
# pragma GCC diagnostic ignored "-Wuseless-cast"
#endif
#include <libxml++/document.h>
-#include <libxml++/nodes/element.h>
#pragma GCC diagnostic pop
#include <filesystem>
#include <fstream>
-#include <functional>
-#include <iosfwd>
#include <slicer/modelParts.h>
#include <slicer/serializer.h>
#include <string>
#include <visibility.h>
+
namespace Glib {
class ustring;
}
namespace Slicer {
- using CurrentElementCreator = ::AdHoc::LazyPointer<xmlpp::Element, xmlpp::Element *>;
-
- class DLL_PUBLIC XmlSerializer : public Serializer {
- protected:
- using ElementCreator = std::function<xmlpp::Element *(xmlpp::Element *, const Glib::ustring &)>;
- static void ModelTreeIterate(xmlpp::Element *, const std::string &, const ModelPartPtr & mp,
- const HookCommon * hp, const ElementCreator &);
- static void ModelTreeIterateRoot(xmlpp::Document *, const std::string &, const ModelPartPtr & mp);
-
- protected:
- static void ModelTreeProcessElement(const CurrentElementCreator &, ModelPartPtr mp, const ElementCreator &);
- static void ModelTreeIterateDictAttrs(xmlpp::Element * element, const ModelPartPtr & dict);
- static void ModelTreeIterateDictElements(xmlpp::Element * element, const ModelPartPtr & dict);
- };
-
- class DLL_PUBLIC XmlDocumentSerializer : public XmlSerializer {
+ class DLL_PUBLIC XmlDocumentSerializer : public Serializer {
public:
- void Serialize(ModelPartForRootPtr) override;
+ void Serialize(ModelPartForRootParam) override;
protected:
xmlpp::Document doc;
@@ -51,7 +33,7 @@ namespace Slicer {
public:
explicit XmlStreamSerializer(std::ostream &);
- void Serialize(ModelPartForRootPtr) override;
+ void Serialize(ModelPartForRootParam) override;
protected:
std::ostream & strm;
@@ -65,41 +47,31 @@ namespace Slicer {
std::ofstream strm;
};
- class DLL_PUBLIC XmlDeserializer : public Deserializer {
- protected:
- static void DocumentTreeIterate(const xmlpp::Node * node, const ModelPartPtr & mp);
- static void DocumentTreeIterateElement(const xmlpp::Element * element, ModelPartPtr mp, const ChildRef & c);
- static void DocumentTreeIterate(const xmlpp::Document * doc, const ModelPartPtr & mp);
- static void DocumentTreeIterateDictAttrs(
- const xmlpp::Element::const_AttributeList & attrs, const ModelPartPtr & dict);
- static void DocumentTreeIterateDictElements(const xmlpp::Element * parent, const ModelPartPtr & dict);
- };
-
- class DLL_PUBLIC XmlStreamDeserializer : public XmlDeserializer {
+ class DLL_PUBLIC XmlStreamDeserializer : public Deserializer {
public:
explicit XmlStreamDeserializer(std::istream &);
- void Deserialize(ModelPartForRootPtr) override;
+ void Deserialize(ModelPartForRootParam) override;
protected:
std::istream & strm;
};
- class DLL_PUBLIC XmlFileDeserializer : public XmlDeserializer {
+ class DLL_PUBLIC XmlFileDeserializer : public Deserializer {
public:
explicit XmlFileDeserializer(std::filesystem::path);
- void Deserialize(ModelPartForRootPtr) override;
+ void Deserialize(ModelPartForRootParam) override;
protected:
const std::filesystem::path path;
};
- class DLL_PUBLIC XmlDocumentDeserializer : public XmlDeserializer {
+ class DLL_PUBLIC XmlDocumentDeserializer : public Deserializer {
public:
explicit XmlDocumentDeserializer(const xmlpp::Document *);
- void Deserialize(ModelPartForRootPtr) override;
+ void Deserialize(ModelPartForRootParam) override;
protected:
const xmlpp::Document * doc;
diff --git a/slicer/xml/testSpecifics.cpp b/slicer/xml/testSpecifics.cpp
index e2d7691..6f94ed4 100644
--- a/slicer/xml/testSpecifics.cpp
+++ b/slicer/xml/testSpecifics.cpp
@@ -1,4 +1,5 @@
#define BOOST_TEST_MODULE xml_specifics
+#include <boost/test/data/test_case.hpp>
#include <boost/test/unit_test.hpp>
#include "serializer.h"
@@ -16,50 +17,67 @@
#include <slicer/slicer.h>
#include <typeinfo>
#include <xmlExceptions.h>
+
// IWYU pragma: no_forward_declare Slicer::BadBooleanValue
// IWYU pragma: no_forward_declare Slicer::XmlDocumentDeserializer
-template<typename T, typename... P>
-T
-BoostThrowWrapperHelper(P &&... p)
+template<typename T>
+const auto BoostThrowWrapperHelper
+ = Slicer::DeserializeAny<Slicer::XmlDocumentDeserializer, T, const xmlpp::Document *>;
+
+template<typename out> using data = std::tuple<const char *, out>;
+BOOST_FIXTURE_TEST_SUITE(doc, xmlpp::DomParser)
+
+BOOST_DATA_TEST_CASE(good_boolean_values,
+ boost::unit_test::data::make<data<bool>>({
+ {"<Boolean>true</Boolean>", true},
+ {"<Boolean>false</Boolean>", false},
+ }),
+ in, exp)
{
- return Slicer::DeserializeAny<Slicer::XmlDocumentDeserializer, T>(std::forward<P>(p)...);
+ parse_memory(in);
+ BOOST_CHECK_EQUAL(exp, BoostThrowWrapperHelper<bool>(get_document()));
}
-BOOST_AUTO_TEST_CASE(boolean_values)
+BOOST_DATA_TEST_CASE(bad_boolean_values,
+ boost::unit_test::data::make({
+ "<Boolean>nonsense</Boolean>",
+ "<Boolean> </Boolean>",
+ "<Boolean></Boolean>",
+ }),
+ in)
{
- xmlpp::DomParser doc;
- doc.parse_memory("<Boolean>true</Boolean>");
- BOOST_REQUIRE_EQUAL(true, BoostThrowWrapperHelper<bool>(doc.get_document()));
- doc.parse_memory("<Boolean>false</Boolean>");
- BOOST_REQUIRE_EQUAL(false, BoostThrowWrapperHelper<bool>(doc.get_document()));
- doc.parse_memory("<Boolean>nonsense</Boolean>");
- BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<bool>(doc.get_document()), Slicer::BadBooleanValue);
- doc.parse_memory("<Boolean> </Boolean>");
- BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<bool>(doc.get_document()), Slicer::BadBooleanValue);
- doc.parse_memory("<Boolean></Boolean>");
- BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<bool>(doc.get_document()), Slicer::BadBooleanValue);
+ parse_memory(in);
+ BOOST_CHECK_THROW(BoostThrowWrapperHelper<bool>(get_document()), Slicer::BadBooleanValue);
}
-BOOST_AUTO_TEST_CASE(int_values)
+BOOST_DATA_TEST_CASE(good_integer_values,
+ boost::unit_test::data::make<data<Ice::Int>>({
+ {"<Int>13</Int>", 13},
+ {"<Int>84</Int>", 84},
+ {"<Int>0</Int>", 0},
+ {"<Int>-4</Int>", -4},
+ }),
+ in, exp)
{
- xmlpp::DomParser doc;
- doc.parse_memory("<Int>13</Int>");
- BOOST_REQUIRE_EQUAL(13, BoostThrowWrapperHelper<Ice::Int>(doc.get_document()));
- doc.parse_memory("<Int>84</Int>");
- BOOST_REQUIRE_EQUAL(84, BoostThrowWrapperHelper<Ice::Int>(doc.get_document()));
- doc.parse_memory("<Int>0</Int>");
- BOOST_REQUIRE_EQUAL(0, BoostThrowWrapperHelper<Ice::Int>(doc.get_document()));
- doc.parse_memory("<Int>-4</Int>");
- BOOST_REQUIRE_EQUAL(-4, BoostThrowWrapperHelper<Ice::Int>(doc.get_document()));
- doc.parse_memory("<Int> </Int>");
- BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<Ice::Int>(doc.get_document()), std::bad_cast);
- doc.parse_memory("<Int>notanint</Int>");
- BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<Ice::Int>(doc.get_document()), std::bad_cast);
- doc.parse_memory("<Int></Int>");
- BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<Ice::Int>(doc.get_document()), std::bad_cast);
+ parse_memory(in);
+ BOOST_CHECK_EQUAL(exp, BoostThrowWrapperHelper<Ice::Int>(get_document()));
}
+BOOST_DATA_TEST_CASE(bad_integer_values,
+ boost::unit_test::data::make({
+ "<Int> </Int>",
+ "<Int>notanint</Int>",
+ "<Int></Int>",
+ }),
+ in)
+{
+ parse_memory(in);
+ BOOST_CHECK_THROW(BoostThrowWrapperHelper<Ice::Int>(get_document()), Slicer::BadNumericValue);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
BOOST_AUTO_TEST_CASE(factories)
{
BOOST_REQUIRE(Slicer::FileSerializerFactory::createNew(".xml", "/some.xml"));
diff --git a/slicer/xml/xmlExceptions.ice b/slicer/xml/xmlExceptions.ice
index 390f458..26d8aa2 100644
--- a/slicer/xml/xmlExceptions.ice
+++ b/slicer/xml/xmlExceptions.ice
@@ -8,6 +8,10 @@ module Slicer {
exception BadBooleanValue extends DeserializerError {
string text;
};
+ ["cpp:ice_print"]
+ exception BadNumericValue extends DeserializerError {
+ string text;
+ };
};
#endif