util.datamapper: Factor out handling of object properties for array reuse
authorKim Alvefur <zash@zash.se>
Sat, 20 Mar 2021 21:25:45 +0100
changeset 11471 88792dd2bee9
parent 11470 c098d07e6717
child 11472 348b191cd850
util.datamapper: Factor out handling of object properties for array reuse
teal-src/util/datamapper.tl
util/datamapper.lua
--- a/teal-src/util/datamapper.tl	Sat Mar 20 20:45:06 2021 +0100
+++ b/teal-src/util/datamapper.tl	Sat Mar 20 21:25:45 2021 +0100
@@ -216,7 +216,87 @@
 	end
 end
 
-local function unparse ( schema : json_schema_object, t : table, current_name : string, current_ns : string, ctx : st.stanza_t ) : st.stanza_t
+local unparse : function (json_schema_object, table, string, string, st.stanza_t) : st.stanza_t
+
+local function unparse_property(out : st.stanza_t, v : any, proptype : json_type_name, propschema : schema_t, value_where : value_goes, name : string, namespace : string, current_ns : string, prefix : string, single_attribute : string)
+	if value_where == "in_attribute" then
+		local attr = name
+		if prefix then
+			attr = prefix .. ':' .. name
+		elseif namespace ~= current_ns then
+			attr = namespace .. "\1" .. name
+		end
+
+		if proptype == "string" and v is string then
+			out.attr[attr] = v
+		elseif proptype == "number" and v is number then
+			out.attr[attr] = string.format("%g", v)
+		elseif proptype == "integer" and v is number then -- TODO is integer
+			out.attr[attr] = string.format("%d", v)
+		elseif proptype == "boolean" then
+			out.attr[attr] = v and "1" or "0"
+		end
+	elseif value_where == "in_text" then
+		if v is string then
+			out:text(v)
+		end
+	elseif value_where == "in_single_attribute" then
+		assert(single_attribute)
+		local propattr : { string : string } = {}
+
+		if namespace ~= current_ns then
+			propattr.xmlns = namespace
+		end
+
+		if proptype == "string" and v is string then
+			propattr[single_attribute] = v
+		elseif proptype == "number" and v is number then
+			propattr[single_attribute] = string.format("%g", v)
+		elseif proptype == "integer" and v is number then -- TODO is integer
+			propattr[single_attribute] = string.format("%d", v)
+		elseif proptype == "boolean" and v is boolean then
+			propattr[single_attribute] = v and "1" or "0"
+		end
+		out:tag(name, propattr):up();
+
+	else
+		local propattr : { string : string }
+		if namespace ~= current_ns then
+			propattr = { xmlns = namespace }
+		end
+		if value_where == "in_tag_name" then
+			if proptype == "string" and v is string then
+				out:tag(v, propattr):up();
+			elseif proptype == "boolean" and v == true then
+				out:tag(name, propattr):up();
+			end
+		elseif proptype == "string" and v is string then
+			out:text_tag(name, v, propattr)
+		elseif proptype == "number" and v is number then
+			out:text_tag(name, string.format("%g", v), propattr)
+		elseif proptype == "integer" and v is number then -- TODO is integer
+			out:text_tag(name, string.format("%d", v), propattr)
+		elseif proptype == "boolean" and v is boolean then
+			out:text_tag(name, v and "1" or "0", propattr)
+		elseif proptype == "object" and propschema is json_schema_object and v is table then
+			local c = unparse(propschema, v, name, namespace);
+			if c then
+				out:add_direct_child(c);
+			end
+		elseif proptype == "array" and propschema is json_schema_object and v is table then
+			if value_where == "in_wrapper" then
+				local c = unparse(propschema, v, name, namespace);
+				if c then
+					out:add_direct_child(c);
+				end
+			else
+				unparse(propschema, v, name, namespace, out);
+			end
+		end
+	end
+end
+
+function unparse ( schema : json_schema_object, t : table, current_name : string, current_ns : string, ctx : st.stanza_t ) : st.stanza_t
 
 	if schema.xml then
 		if schema.xml.name then
@@ -236,85 +316,8 @@
 			local v = t[prop]
 
 			if v ~= nil then
-
 				local proptype, value_where, name, namespace, prefix, single_attribute = unpack_propschema(propschema, prop, current_ns)
-
-				if value_where == "in_attribute" then
-					local attr = name
-					if prefix then
-						attr = prefix .. ':' .. name
-					elseif namespace ~= current_ns then
-						attr = namespace .. "\1" .. name
-					end
-
-					if proptype == "string" and v is string then
-						out.attr[attr] = v
-					elseif proptype == "number" and v is number then
-						out.attr[attr] = string.format("%g", v)
-					elseif proptype == "integer" and v is number then -- TODO is integer
-						out.attr[attr] = string.format("%d", v)
-					elseif proptype == "boolean" then
-						out.attr[attr] = v and "1" or "0"
-					end
-				elseif value_where == "in_text" then
-					if v is string then
-						out:text(v)
-					end
-				elseif value_where == "in_single_attribute" then
-					local propattr : { string : string } = {}
-
-					if namespace ~= current_ns then
-						propattr.xmlns = namespace
-					end
-
-					if proptype == "string" and v is string then
-						propattr[single_attribute] = v
-					elseif proptype == "number" and v is number then
-						propattr[single_attribute] = string.format("%g", v)
-					elseif proptype == "integer" and v is number then -- TODO is integer
-						propattr[single_attribute] = string.format("%d", v)
-					elseif proptype == "boolean" and v is boolean then
-						propattr[single_attribute] = v and "1" or "0"
-					end
-					out:tag(name, propattr):up();
-
-				else
-					local propattr : { string : string }
-					if namespace ~= current_ns then
-						propattr = { xmlns = namespace }
-					end
-					if value_where == "in_tag_name" then
-						if proptype == "string" and v is string then
-							out:tag(v, propattr):up();
-						elseif proptype == "boolean" and v == true then
-							out:tag(name, propattr):up();
-						end
-					elseif proptype == "string" and v is string then
-						out:text_tag(name, v, propattr)
-					elseif proptype == "number" and v is number then
-						out:text_tag(name, string.format("%g", v), propattr)
-					elseif proptype == "integer" and v is number then -- TODO is integer
-						out:text_tag(name, string.format("%d", v), propattr)
-					elseif proptype == "boolean" and v is boolean then
-						out:text_tag(name, v and "1" or "0", propattr)
-					elseif proptype == "object" and propschema is json_schema_object and v is table then
-						local c = unparse(propschema, v, name, namespace);
-						if c then
-							out:add_direct_child(c);
-						end
-					elseif proptype == "array" and propschema is json_schema_object and v is table then
-						if value_where == "in_wrapper" then
-							local c = unparse(propschema, v, name, namespace);
-							if c then
-								out:add_direct_child(c);
-							end
-						else
-							unparse(propschema, v, name, namespace, out);
-						end
-					else
-						error "NYI"
-					end
-				end
+				unparse_property(out, v, proptype, propschema, value_where, name, namespace, current_ns, prefix, single_attribute)
 			end
 		end
 		return out;
--- a/util/datamapper.lua	Sat Mar 20 20:45:06 2021 +0100
+++ b/util/datamapper.lua	Sat Mar 20 21:25:45 2021 +0100
@@ -183,7 +183,87 @@
 	end
 end
 
-local function unparse(schema, t, current_name, current_ns, ctx)
+local unparse
+
+local function unparse_property(out, v, proptype, propschema, value_where, name, namespace, current_ns, prefix, single_attribute)
+	if value_where == "in_attribute" then
+		local attr = name
+		if prefix then
+			attr = prefix .. ":" .. name
+		elseif namespace ~= current_ns then
+			attr = namespace .. "\1" .. name
+		end
+
+		if proptype == "string" and type(v) == "string" then
+			out.attr[attr] = v
+		elseif proptype == "number" and type(v) == "number" then
+			out.attr[attr] = string.format("%g", v)
+		elseif proptype == "integer" and type(v) == "number" then
+			out.attr[attr] = string.format("%d", v)
+		elseif proptype == "boolean" then
+			out.attr[attr] = v and "1" or "0"
+		end
+	elseif value_where == "in_text" then
+		if type(v) == "string" then
+			out:text(v)
+		end
+	elseif value_where == "in_single_attribute" then
+		assert(single_attribute)
+		local propattr = {}
+
+		if namespace ~= current_ns then
+			propattr.xmlns = namespace
+		end
+
+		if proptype == "string" and type(v) == "string" then
+			propattr[single_attribute] = v
+		elseif proptype == "number" and type(v) == "number" then
+			propattr[single_attribute] = string.format("%g", v)
+		elseif proptype == "integer" and type(v) == "number" then
+			propattr[single_attribute] = string.format("%d", v)
+		elseif proptype == "boolean" and type(v) == "boolean" then
+			propattr[single_attribute] = v and "1" or "0"
+		end
+		out:tag(name, propattr):up();
+
+	else
+		local propattr
+		if namespace ~= current_ns then
+			propattr = {xmlns = namespace}
+		end
+		if value_where == "in_tag_name" then
+			if proptype == "string" and type(v) == "string" then
+				out:tag(v, propattr):up();
+			elseif proptype == "boolean" and v == true then
+				out:tag(name, propattr):up();
+			end
+		elseif proptype == "string" and type(v) == "string" then
+			out:text_tag(name, v, propattr)
+		elseif proptype == "number" and type(v) == "number" then
+			out:text_tag(name, string.format("%g", v), propattr)
+		elseif proptype == "integer" and type(v) == "number" then
+			out:text_tag(name, string.format("%d", v), propattr)
+		elseif proptype == "boolean" and type(v) == "boolean" then
+			out:text_tag(name, v and "1" or "0", propattr)
+		elseif proptype == "object" and type(propschema) == "table" and type(v) == "table" then
+			local c = unparse(propschema, v, name, namespace);
+			if c then
+				out:add_direct_child(c);
+			end
+		elseif proptype == "array" and type(propschema) == "table" and type(v) == "table" then
+			if value_where == "in_wrapper" then
+				local c = unparse(propschema, v, name, namespace);
+				if c then
+					out:add_direct_child(c);
+				end
+			else
+				unparse(propschema, v, name, namespace, out);
+			end
+		end
+	end
+end
+
+function unparse(schema, t, current_name, current_ns, ctx)
 
 	if schema.xml then
 		if schema.xml.name then
@@ -203,85 +283,8 @@
 			local v = t[prop]
 
 			if v ~= nil then
-
 				local proptype, value_where, name, namespace, prefix, single_attribute = unpack_propschema(propschema, prop, current_ns)
-
-				if value_where == "in_attribute" then
-					local attr = name
-					if prefix then
-						attr = prefix .. ":" .. name
-					elseif namespace ~= current_ns then
-						attr = namespace .. "\1" .. name
-					end
-
-					if proptype == "string" and type(v) == "string" then
-						out.attr[attr] = v
-					elseif proptype == "number" and type(v) == "number" then
-						out.attr[attr] = string.format("%g", v)
-					elseif proptype == "integer" and type(v) == "number" then
-						out.attr[attr] = string.format("%d", v)
-					elseif proptype == "boolean" then
-						out.attr[attr] = v and "1" or "0"
-					end
-				elseif value_where == "in_text" then
-					if type(v) == "string" then
-						out:text(v)
-					end
-				elseif value_where == "in_single_attribute" then
-					local propattr = {}
-
-					if namespace ~= current_ns then
-						propattr.xmlns = namespace
-					end
-
-					if proptype == "string" and type(v) == "string" then
-						propattr[single_attribute] = v
-					elseif proptype == "number" and type(v) == "number" then
-						propattr[single_attribute] = string.format("%g", v)
-					elseif proptype == "integer" and type(v) == "number" then
-						propattr[single_attribute] = string.format("%d", v)
-					elseif proptype == "boolean" and type(v) == "boolean" then
-						propattr[single_attribute] = v and "1" or "0"
-					end
-					out:tag(name, propattr):up();
-
-				else
-					local propattr
-					if namespace ~= current_ns then
-						propattr = {xmlns = namespace}
-					end
-					if value_where == "in_tag_name" then
-						if proptype == "string" and type(v) == "string" then
-							out:tag(v, propattr):up();
-						elseif proptype == "boolean" and v == true then
-							out:tag(name, propattr):up();
-						end
-					elseif proptype == "string" and type(v) == "string" then
-						out:text_tag(name, v, propattr)
-					elseif proptype == "number" and type(v) == "number" then
-						out:text_tag(name, string.format("%g", v), propattr)
-					elseif proptype == "integer" and type(v) == "number" then
-						out:text_tag(name, string.format("%d", v), propattr)
-					elseif proptype == "boolean" and type(v) == "boolean" then
-						out:text_tag(name, v and "1" or "0", propattr)
-					elseif proptype == "object" and type(propschema) == "table" and type(v) == "table" then
-						local c = unparse(propschema, v, name, namespace);
-						if c then
-							out:add_direct_child(c);
-						end
-					elseif proptype == "array" and type(propschema) == "table" and type(v) == "table" then
-						if value_where == "in_wrapper" then
-							local c = unparse(propschema, v, name, namespace);
-							if c then
-								out:add_direct_child(c);
-							end
-						else
-							unparse(propschema, v, name, namespace, out);
-						end
-					else
-						error("NYI")
-					end
-				end
+				unparse_property(out, v, proptype, propschema, value_where, name, namespace, current_ns, prefix, single_attribute)
 			end
 		end
 		return out