diff options
-rw-r--r-- | slicer/db/sqlInsertSerializer.cpp | 8 | ||||
-rw-r--r-- | slicer/db/sqlUpdateSerializer.cpp | 8 | ||||
-rw-r--r-- | slicer/json/serializer.cpp | 53 | ||||
-rw-r--r-- | slicer/slicer/modelParts.cpp | 3 | ||||
-rw-r--r-- | slicer/slicer/modelParts.h | 8 | ||||
-rw-r--r-- | slicer/slicer/modelPartsTypes.h | 14 | ||||
-rw-r--r-- | slicer/slicer/modelPartsTypes.impl.h | 51 | ||||
-rw-r--r-- | slicer/test/conversions.cpp | 20 | ||||
-rw-r--r-- | slicer/test/conversions.h | 6 | ||||
-rw-r--r-- | slicer/test/initial/optionals2.json | 1 | ||||
-rw-r--r-- | slicer/test/initial/optionals3.json | 1 | ||||
-rw-r--r-- | slicer/test/initial/optionals5.json | 1 | ||||
-rw-r--r-- | slicer/test/optionals.ice | 6 | ||||
-rw-r--r-- | slicer/test/preprocessor.cpp | 2 | ||||
-rw-r--r-- | slicer/test/serializers.cpp | 38 | ||||
-rw-r--r-- | slicer/tool/parser.cpp | 6 | ||||
-rw-r--r-- | slicer/xml/serializer.cpp | 32 | ||||
-rw-r--r-- | slicer/xml/serializer.h | 5 |
18 files changed, 177 insertions, 86 deletions
diff --git a/slicer/db/sqlInsertSerializer.cpp b/slicer/db/sqlInsertSerializer.cpp index 04eae93..cd10366 100644 --- a/slicer/db/sqlInsertSerializer.cpp +++ b/slicer/db/sqlInsertSerializer.cpp @@ -96,12 +96,10 @@ namespace Slicer { SqlInsertSerializer::bindObjectAndExecuteField(int & paramNo, DB::ModifyCommand * ins, Slicer::ModelPartPtr cmp, HookCommonPtr h) const { if (isBind(h)) { - if (cmp->HasValue()) { - cmp->GetValue(new SqlBinder(*ins, paramNo++)); - } - else { - ins->bindNull(paramNo++); + if (!cmp->GetValue(new SqlBinder(*ins, paramNo))) { + ins->bindNull(paramNo); } + paramNo++; } } diff --git a/slicer/db/sqlUpdateSerializer.cpp b/slicer/db/sqlUpdateSerializer.cpp index f07c421..394c660 100644 --- a/slicer/db/sqlUpdateSerializer.cpp +++ b/slicer/db/sqlUpdateSerializer.cpp @@ -51,12 +51,10 @@ namespace Slicer { int paramNo = 0; cmp->OnEachChild([&upd, ¶mNo](const std::string &, ModelPartPtr cmp, HookCommonPtr h) { if (isValue(h)) { - if (cmp->HasValue()) { - cmp->GetValue(new SqlBinder(*upd, paramNo++)); - } - else { - upd->bindNull(paramNo++); + if (!cmp->GetValue(new SqlBinder(*upd, paramNo))) { + upd->bindNull(paramNo); } + paramNo++; } }); cmp->OnEachChild([&upd, ¶mNo](const std::string &, ModelPartPtr cmp, HookCommonPtr h) { diff --git a/slicer/json/serializer.cpp b/slicer/json/serializer.cpp index 5402cbf..9429b9e 100644 --- a/slicer/json/serializer.cpp +++ b/slicer/json/serializer.cpp @@ -218,41 +218,48 @@ namespace Slicer { void JsonSerializer::ModelTreeIterate(json::Value * n, const std::string & name, ModelPartPtr mp) { - if (name.empty() || !n) { + if (name.empty() || !n || !mp) { return; } - if (mp && mp->HasValue()) { - switch (mp->GetType()) { - case mpt_Null: - boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value())}); - return; - case mpt_Simple: - mp->GetValue(new JsonValueTarget(*boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value())}).first->second)); + switch (mp->GetType()) { + case mpt_Null: + boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value())}); + return; + case mpt_Simple: + { + json::Value v; + if (mp->GetValue(new JsonValueTarget(v))) { + boost::get<json::Object>(*n).insert({ name, json::ValuePtr(new json::Value(v)) }); + } break; - case mpt_Complex: - { - auto nn = json::ValuePtr(new json::Value(json::Object())); - if (auto typeIdName = mp->GetTypeIdProperty()) { - if (auto typeId = mp->GetTypeId()) { - boost::get<json::Object>(*nn).insert({*typeIdName, json::ValuePtr(new json::Value(*typeId))}); - mp = mp->GetSubclassModelPart(*typeId); - } + } + case mpt_Complex: + if (mp->HasValue()) { + auto nn = json::ValuePtr(new json::Value(json::Object())); + if (auto typeIdName = mp->GetTypeIdProperty()) { + if (auto typeId = mp->GetTypeId()) { + boost::get<json::Object>(*nn).insert({*typeIdName, json::ValuePtr(new json::Value(*typeId))}); + mp = mp->GetSubclassModelPart(*typeId); } - mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterate, boost::get<json::Object>(*n).insert({name, nn}).first->second.get(), _1, _2)); - break; } - case mpt_Sequence: + mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterate, boost::get<json::Object>(*n).insert({name, nn}).first->second.get(), _1, _2)); + } + break; + case mpt_Sequence: + if (mp->HasValue()) { mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterateSeq, boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value(json::Array()))}).first->second.get(), _2)); - break; - case mpt_Dictionary: + } + break; + case mpt_Dictionary: + if (mp->HasValue()) { if (metaDataFlagSet(mp->GetMetadata(), md_object)) { mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterateDictObj, boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value(json::Object()))}).first->second.get(), _2)); } else { mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterateSeq, boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value(json::Array()))}).first->second.get(), _2)); } - break; - } + } + break; } } diff --git a/slicer/slicer/modelParts.cpp b/slicer/slicer/modelParts.cpp index e33d110..6b26fe7 100644 --- a/slicer/slicer/modelParts.cpp +++ b/slicer/slicer/modelParts.cpp @@ -87,9 +87,10 @@ namespace Slicer { { } - void + bool ModelPart::GetValue(ValueTargetPtr) { + return false; } const Metadata & diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h index e0f49c4..611d370 100644 --- a/slicer/slicer/modelParts.h +++ b/slicer/slicer/modelParts.h @@ -103,6 +103,12 @@ namespace Slicer { mpt_Dictionary, }; + enum TryConvertResult { + tcr_NoAction = 0, + tcr_NoValue, + tcr_Value, + }; + class ChildRef : virtual public IceUtil::Shared { public: virtual ModelPartPtr Child() const = 0; @@ -169,7 +175,7 @@ namespace Slicer { virtual void Create(); virtual void Complete(); virtual void SetValue(ValueSourcePtr); - virtual void GetValue(ValueTargetPtr); + virtual bool GetValue(ValueTargetPtr); virtual bool HasValue() const = 0; virtual const Metadata & GetMetadata() const; virtual bool IsOptional() const; diff --git a/slicer/slicer/modelPartsTypes.h b/slicer/slicer/modelPartsTypes.h index 52b7c62..62280cc 100644 --- a/slicer/slicer/modelPartsTypes.h +++ b/slicer/slicer/modelPartsTypes.h @@ -44,7 +44,7 @@ namespace Slicer { ModelPartForSimple(T * h); virtual void SetValue(ValueSourcePtr s) override; - virtual void GetValue(ValueTargetPtr s) override; + virtual bool GetValue(ValueTargetPtr s) override; }; class DLL_PUBLIC ModelPartForConvertedBase : public ModelPart { @@ -62,9 +62,9 @@ namespace Slicer { template<typename ET, typename MT> inline static bool tryConvertFrom(const ValueSourcePtr & vsp, MT * model); template<typename ET, typename MT, typename Conv> - inline static bool tryConvertTo(const ValueTargetPtr & vsp, const MT * model, const Conv & conv); + inline static TryConvertResult tryConvertTo(const ValueTargetPtr & vsp, const MT * model, const Conv & conv); template<typename ET, typename MT> - inline static bool tryConvertTo(const ValueTargetPtr & vsp, const MT * model); + inline static TryConvertResult tryConvertTo(const ValueTargetPtr & vsp, const MT * model); }; template<typename T, typename M, T M::* MV> @@ -75,7 +75,7 @@ namespace Slicer { ModelPartForConverted(T * h); virtual void SetValue(ValueSourcePtr s) override; - virtual void GetValue(ValueTargetPtr s) override; + virtual bool GetValue(ValueTargetPtr s) override; }; template<typename T, typename M, IceUtil::Optional<T> M::* MV> @@ -86,7 +86,7 @@ namespace Slicer { ModelPartForConverted(IceUtil::Optional<T> * h); virtual void SetValue(ValueSourcePtr s) override; - virtual void GetValue(ValueTargetPtr s) override; + virtual bool GetValue(ValueTargetPtr s) override; virtual bool HasValue() const override; }; @@ -111,7 +111,7 @@ namespace Slicer { public: ModelPartForOptional(IceUtil::Optional< typename T::element_type > * h); virtual void Create() override; - virtual void GetValue(ValueTargetPtr s) override; + virtual bool GetValue(ValueTargetPtr s) override; virtual ModelPartType GetType() const override; protected: @@ -248,7 +248,7 @@ namespace Slicer { virtual void SetValue(ValueSourcePtr s) override; - virtual void GetValue(ValueTargetPtr s) override; + virtual bool GetValue(ValueTargetPtr s) override; static const Metadata metadata; static const Enumerations enumerations; diff --git a/slicer/slicer/modelPartsTypes.impl.h b/slicer/slicer/modelPartsTypes.impl.h index 2d6d169..2fe6401 100644 --- a/slicer/slicer/modelPartsTypes.impl.h +++ b/slicer/slicer/modelPartsTypes.impl.h @@ -156,10 +156,11 @@ namespace Slicer { } template<typename T> - void ModelPartForSimple<T>::GetValue(ValueTargetPtr s) + bool ModelPartForSimple<T>::GetValue(ValueTargetPtr s) { BOOST_ASSERT(this->Model); s->get(*this->Model); + return true; } // ModelPartForConverted @@ -202,6 +203,8 @@ namespace Slicer { T & operator()(IceUtil::Optional<Y> & x) const { if (!x) x = Y(); return *x; } template <typename Y> const T & operator()(const IceUtil::Optional<Y> & x) const { return *x; } + static bool valueExists(const T &) { return true; } + static bool valueExists(const IceUtil::Optional<T> & y) { return y; } }; template <typename X> struct Coerce<IceUtil::Optional<X>> { @@ -211,16 +214,9 @@ namespace Slicer { const IceUtil::Optional<T> & operator()(const IceUtil::Optional<T> & x) const { return x; } template <typename Y> IceUtil::Optional<T> operator()(Y & y) const { return y; } + static bool valueExists(const T &) { return true; } }; - // Value exists check - template <typename X, typename Y> - typename std::enable_if<std::is_constructible<X, Y>::value, bool>::type - valueExists(const Y &) { return true; } - template <typename X, typename Y> - typename std::enable_if<std::is_constructible<X, Y>::value, bool>::type - valueExists(const IceUtil::Optional<Y> & y) { return y; } - template<typename ET, typename MT, typename Conv> inline bool ModelPartForConvertedBase::tryConvertFrom(const ValueSourcePtr & vsp, MT * model, const Conv & conv) @@ -230,7 +226,7 @@ namespace Slicer { ET tmp; vspt->set(tmp); auto converted = conv(Coerce<CA>()(tmp)); - if (valueExists<MT>(converted)) { + if (Coerce<MT>::valueExists(converted)) { *model = Coerce<MT>()(converted); } return true; @@ -243,7 +239,7 @@ namespace Slicer { bool ModelPartForConvertedBase::tryConvertFrom(const ValueSourcePtr & vsp, MT * model) { if (auto vspt = dynamic_cast<TValueSource<ET> *>(vsp.get())) { - if (valueExists<ET>(*model)) { + if (Coerce<ET>::valueExists(*model)) { vspt->set(Coerce<ET>()(*model)); } return true; @@ -253,32 +249,35 @@ namespace Slicer { template<typename ET, typename MT, typename Conv> inline - bool ModelPartForConvertedBase::tryConvertTo(const ValueTargetPtr & vsp, const MT * model, const Conv & conv) + TryConvertResult ModelPartForConvertedBase::tryConvertTo(const ValueTargetPtr & vsp, const MT * model, const Conv & conv) { if (auto vspt = dynamic_cast<TValueTarget<ET> *>(vsp.get())) { typedef typename callable_traits<Conv>::template arg<0>::type CA; - if (valueExists<CA>(*model)) { + typedef typename std::remove_const<typename std::remove_reference<CA>::type>::type CAR; + if (Coerce<CAR>::valueExists(*model)) { auto converted = conv(Coerce<CA>()(*model)); - if (valueExists<ET>(converted)) { + if (Coerce<ET>::valueExists(converted)) { vspt->get(Coerce<ET>()(converted)); + return tcr_Value; } } - return true; + return tcr_NoValue; } - return false; + return tcr_NoAction; } template<typename ET, typename MT> inline - bool ModelPartForConvertedBase::tryConvertTo(const ValueTargetPtr & vsp, const MT * model) + TryConvertResult ModelPartForConvertedBase::tryConvertTo(const ValueTargetPtr & vsp, const MT * model) { if (auto vspt = dynamic_cast<TValueTarget<ET> *>(vsp.get())) { - if (valueExists<ET>(*model)) { + if (Coerce<ET>::valueExists(*model)) { vspt->get(Coerce<ET>()(*model)); + return tcr_Value; } - return true; + return tcr_NoValue; } - return false; + return tcr_NoAction; } // ModelPartForOptional @@ -310,14 +309,13 @@ namespace Slicer { } template<typename T> - void ModelPartForOptional<T>::GetValue(ValueTargetPtr s) + bool ModelPartForOptional<T>::GetValue(ValueTargetPtr s) { BOOST_ASSERT(this->Model); - if (!*this->Model) { - *this->Model = typename T::element_type(); - modelPart = new T(&**this->Model); + if (*this->Model) { + return modelPart->GetValue(s); } - modelPart->GetValue(s); + return false; } template<typename T> @@ -556,10 +554,11 @@ namespace Slicer { } template<typename T> - void ModelPartForEnum<T>::GetValue(ValueTargetPtr s) + bool ModelPartForEnum<T>::GetValue(ValueTargetPtr s) { BOOST_ASSERT(this->Model); s->get(lookup(*this->Model)); + return true; } // ModelPartForSequence diff --git a/slicer/test/conversions.cpp b/slicer/test/conversions.cpp index 2d1ef2c..9ac43e3 100644 --- a/slicer/test/conversions.cpp +++ b/slicer/test/conversions.cpp @@ -104,6 +104,26 @@ namespace Slicer { { return boost::posix_time::time_duration((ts->days * 24) + ts->hours, ts->minutes, ts->seconds); } + + DLL_PUBLIC + IceUtil::Optional<Ice::Int> + str2int(const std::string & s) + { + if (s.empty()) { + return IceUtil::None; + } + return boost::lexical_cast<Ice::Int>(s); + } + + DLL_PUBLIC + std::string + int2str(const IceUtil::Optional<Ice::Int> & i) + { + if (!i) { + return std::string(); + } + return boost::lexical_cast<std::string>(*i); + } } namespace TestModule { diff --git a/slicer/test/conversions.h b/slicer/test/conversions.h index 76dcd97..dfc76c6 100644 --- a/slicer/test/conversions.h +++ b/slicer/test/conversions.h @@ -30,6 +30,12 @@ namespace Slicer { DLL_PUBLIC std::string dateTimeToString(const ::TestModule::DateTime & in); + DLL_PUBLIC + IceUtil::Optional<Ice::Int> + str2int(const std::string &); + DLL_PUBLIC + std::string + int2str(const IceUtil::Optional<Ice::Int> &); } #endif diff --git a/slicer/test/initial/optionals2.json b/slicer/test/initial/optionals2.json new file mode 100644 index 0000000..7bc047b --- /dev/null +++ b/slicer/test/initial/optionals2.json @@ -0,0 +1 @@ +{"nonOptConverted":"4","optConverted":""} diff --git a/slicer/test/initial/optionals3.json b/slicer/test/initial/optionals3.json new file mode 100644 index 0000000..1c9dccf --- /dev/null +++ b/slicer/test/initial/optionals3.json @@ -0,0 +1 @@ +{"nonOptConverted":"4","optConverted":"10"} diff --git a/slicer/test/initial/optionals5.json b/slicer/test/initial/optionals5.json new file mode 100644 index 0000000..1e0d3fc --- /dev/null +++ b/slicer/test/initial/optionals5.json @@ -0,0 +1 @@ +{"nonOptConverted":"4"} diff --git a/slicer/test/optionals.ice b/slicer/test/optionals.ice index d037e67..c4c7436 100644 --- a/slicer/test/optionals.ice +++ b/slicer/test/optionals.ice @@ -15,6 +15,12 @@ module TestModule { [ "slicer:conversion:boost.posix_time.ptime:boost.posix_time.to_iso_extended_string:boost.posix_time.time_from_string:nodeclare" ] optional(5) string optConverted; }; + class Optionals2 { + [ "slicer:conversion:std.string:Slicer.str2int:Slicer.int2str:nodeclare" ] + optional(0) int optConverted; + [ "slicer:conversion:std.string:Slicer.str2int:Slicer.int2str:nodeclare" ] + int nonOptConverted; + }; }; #endif diff --git a/slicer/test/preprocessor.cpp b/slicer/test/preprocessor.cpp index 869c2a0..7d81f5e 100644 --- a/slicer/test/preprocessor.cpp +++ b/slicer/test/preprocessor.cpp @@ -20,7 +20,7 @@ ComponentsCount COMPONENTS_IN_TEST_ICE = { { "interfaces.ice", 0 }, { "json.ice", 2 }, { "locals.ice", 7 }, - { "optionals.ice", 1 }, + { "optionals.ice", 2 }, { "structs.ice", 4 }, { "types.ice", 3 }, { "xml.ice", 5 } diff --git a/slicer/test/serializers.cpp b/slicer/test/serializers.cpp index cfbe794..8fee506 100644 --- a/slicer/test/serializers.cpp +++ b/slicer/test/serializers.cpp @@ -33,7 +33,15 @@ class FileBased { void verifyByFile(const fs::path & infile, const boost::function<void(const T &)> & check = NULL) { + verifyByFile<T, DeserializerIn>(infile, infile, check); + } + + template<typename T, typename DeserializerIn> + void + verifyByFile(const fs::path & infile, const fs::path & expOutFile, const boost::function<void(const T &)> & check = NULL) + { const fs::path input = rootDir / "initial" / infile; + const fs::path expected = rootDir / "initial" / expOutFile; const fs::path tmpf = binDir / "byFile"; fs::create_directory(tmpf); const fs::path output = tmpf / infile; @@ -60,7 +68,7 @@ class FileBased { } BOOST_TEST_CHECKPOINT("Checksum: " << input << " === " << output); - diff(input, output); + diff(expected, output); } template<typename T, typename Deserializer, typename Serializer, typename Internal> @@ -521,6 +529,34 @@ BOOST_AUTO_TEST_CASE( xml_simpleArray ) verifyByFile<TestModule::SimpleSeq, Slicer::XmlFileDeserializer>("simpleArray2.xml"); } +BOOST_AUTO_TEST_CASE( json_emptyToNull ) +{ + verifyByFile<TestModule::Optionals2Ptr, Slicer::JsonFileDeserializer>("optionals2.json", [](const auto & o) { + BOOST_REQUIRE(o); + BOOST_REQUIRE(!o->optConverted); + BOOST_REQUIRE_EQUAL(o->nonOptConverted, 4); + }); +} + +BOOST_AUTO_TEST_CASE( json_emptyToNull_withValue ) +{ + verifyByFile<TestModule::Optionals2Ptr, Slicer::JsonFileDeserializer>("optionals3.json", [](const auto & o) { + BOOST_REQUIRE(o); + BOOST_REQUIRE(o->optConverted); + BOOST_REQUIRE_EQUAL(*o->optConverted, 10); + BOOST_REQUIRE_EQUAL(o->nonOptConverted, 4); + }); +} + +BOOST_AUTO_TEST_CASE( json_emptyToNull_omitted ) +{ + verifyByFile<TestModule::Optionals2Ptr, Slicer::JsonFileDeserializer>("optionals5.json", "optionals2.json", [](const auto & o) { + BOOST_REQUIRE(o); + BOOST_REQUIRE(!o->optConverted); + BOOST_REQUIRE_EQUAL(o->nonOptConverted, 4); + }); +} + BOOST_AUTO_TEST_CASE( json_streams ) { const auto tmpf = binDir / "byStream"; diff --git a/slicer/tool/parser.cpp b/slicer/tool/parser.cpp index de3f699..fbe86d4 100644 --- a/slicer/tool/parser.cpp +++ b/slicer/tool/parser.cpp @@ -70,19 +70,19 @@ namespace Slicer { Slice::typeToString(type)); fprintbf(cpp, "}\n\n"); - fprintbf(cpp, "template<> DLL_PUBLIC\nvoid\n"); + fprintbf(cpp, "template<> DLL_PUBLIC\nbool\n"); createModelPartForConverted(type, c->scoped(), dm); fprintbf(cpp, "::GetValue(ValueTargetPtr vtp)\n{\n"); fprintbf(cpp, "\tBOOST_ASSERT(Model);\n"); for (const auto & conversion : conversions) { - fprintbf(cpp, "\tif (tryConvertTo< %s >(vtp, Model, &%s)) return;\n", + fprintbf(cpp, "\tif (auto r = tryConvertTo< %s >(vtp, Model, &%s)) return (r == tcr_Value);\n", conversion.ExchangeType, conversion.ConvertToExchangeFunc); } // Default conversion if (!dm->hasMetaData("slicer:nodefaultconversion")) { - fprintbf(cpp, "\tif (tryConvertTo< %s >(vtp, Model)) return;\n", + fprintbf(cpp, "\tif (auto r = tryConvertTo< %s >(vtp, Model)) return (r == tcr_Value);\n", Slice::typeToString(type)); } // Failed to convert diff --git a/slicer/xml/serializer.cpp b/slicer/xml/serializer.cpp index 899b789..8aa9552 100644 --- a/slicer/xml/serializer.cpp +++ b/slicer/xml/serializer.cpp @@ -172,6 +172,11 @@ namespace Slicer { XmlValueTarget(boost::bind(&xmlpp::Element::set_first_child_text, p, _1)) { } + + XmlContentValueTarget(const CurrentElementCreator & cec) : + XmlValueTarget(boost::bind(&xmlpp::Element::set_first_child_text, boost::bind(&CurrentElementCreator::deref, &cec), _1)) + { + } }; void @@ -294,7 +299,7 @@ namespace Slicer { void XmlSerializer::ModelTreeIterate(xmlpp::Element * n, const std::string & name, ModelPartPtr mp, HookCommonPtr hp, const ElementCreator & ec) { - if (!mp->HasValue() || name.empty()) { + if (name.empty()) { return; } if (hp && metaDataFlagSet(hp->GetMetadata(), md_attribute)) { @@ -314,7 +319,8 @@ namespace Slicer { ModelTreeProcessElement(n, mp, boost::bind(&xmlpp::Element::add_child_element, _1, name, Glib::ustring())); } else { - ModelTreeProcessElement(ec(n, name), mp, defaultElementCreator); + CurrentElementCreator cec(boost::bind(ec, n, name)); + ModelTreeProcessElement(cec, mp, defaultElementCreator); } } } @@ -337,25 +343,27 @@ namespace Slicer { dict->OnEachChild([element](const auto &, const auto & mp, const auto &) { if (mp->HasValue()) { mp->GetChild(keyName)->GetValue(new XmlValueTarget([&mp,element](const auto & name) { - ModelTreeProcessElement(element->add_child_element(name), mp->GetChild(valueName), defaultElementCreator); + CurrentElementCreator cec([&element, &name]() { return element->add_child_element(name); }); + ModelTreeProcessElement(cec, mp->GetChild(valueName), defaultElementCreator); })); } }); } void - XmlSerializer::ModelTreeProcessElement(xmlpp::Element * element, ModelPartPtr mp, const ElementCreator & ec) + XmlSerializer::ModelTreeProcessElement(const CurrentElementCreator & cec, ModelPartPtr mp, const ElementCreator & ec) { - auto typeIdPropName = mp->GetTypeIdProperty(); - auto typeId = mp->GetTypeId(); - if (typeId && typeIdPropName) { - element->set_attribute(*typeIdPropName, *typeId); - mp = mp->GetSubclassModelPart(*typeId); - } if (mp->GetType() == mpt_Simple) { - mp->GetValue(new XmlContentValueTarget(element)); + mp->GetValue(new XmlContentValueTarget(cec)); } - else { + 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(boost::bind(&XmlSerializer::ModelTreeIterate, element, _1, _2, _3, ec)); } } diff --git a/slicer/xml/serializer.h b/slicer/xml/serializer.h index 5521dc4..e13b5b5 100644 --- a/slicer/xml/serializer.h +++ b/slicer/xml/serializer.h @@ -5,8 +5,11 @@ #include <libxml++/document.h> #include <libxml++/nodes/element.h> #include <visibility.h> +#include <lazyPointer.h> namespace Slicer { + typedef ::AdHoc::LazyPointer<xmlpp::Element, xmlpp::Element *> CurrentElementCreator; + class DLL_PUBLIC XmlSerializer : public Serializer { protected: typedef boost::function<xmlpp::Element *(xmlpp::Element *, const Glib::ustring &)> ElementCreator; @@ -14,7 +17,7 @@ namespace Slicer { static void ModelTreeIterateRoot(xmlpp::Document *, const std::string &, ModelPartPtr mp); protected: - static void ModelTreeProcessElement(xmlpp::Element * n, ModelPartPtr mp, const ElementCreator &); + static void ModelTreeProcessElement(const CurrentElementCreator &, ModelPartPtr mp, const ElementCreator &); static void ModelTreeIterateDictAttrs(xmlpp::Element * element, ModelPartPtr dict); static void ModelTreeIterateDictElements(xmlpp::Element * element, ModelPartPtr dict); }; |