diff options
Diffstat (limited to 'slicer/xml')
-rw-r--r-- | slicer/xml/serializer.cpp | 724 | ||||
-rw-r--r-- | slicer/xml/serializer.h | 48 | ||||
-rw-r--r-- | slicer/xml/testSpecifics.cpp | 82 | ||||
-rw-r--r-- | slicer/xml/xmlExceptions.ice | 4 |
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 |