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);  	};  | 
