scansion/ordered_serializer.lua

changeset 174
662bd8c5ae28
child 178
e547ddf8b64d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scansion/ordered_serializer.lua	Thu Mar 23 15:12:30 2023 +0000
@@ -0,0 +1,56 @@
+local s_find, s_gsub, s_match = string.find, string.gsub, string.match;
+local t_concat, t_insert = table.concat, table.insert;
+
+local pairs = require "util.iterators".sorted_pairs;
+
+local escape_table = { ["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;" };
+local function xml_escape(str) return (s_gsub(str, "['&<>\"]", escape_table)); end
+
+local function _dostring(t, buf, self, _xml_escape, parentns)
+	local nsid = 0;
+	local name = t.name
+	t_insert(buf, "<"..name);
+	for k, v in pairs(t.attr) do
+		if s_find(k, "\1", 1, true) then
+			local ns, attrk = s_match(k, "^([^\1]*)\1?(.*)$");
+			nsid = nsid + 1;
+			t_insert(buf, " xmlns:ns"..nsid.."='".._xml_escape(ns).."' ".."ns"..nsid..":"..attrk.."='".._xml_escape(v).."'");
+		elseif not(k == "xmlns" and v == parentns) then
+			t_insert(buf, " "..k.."='".._xml_escape(v).."'");
+		end
+	end
+	local len = #t;
+	if len == 0 then
+		t_insert(buf, "/>");
+	else
+		t_insert(buf, ">");
+		for n=1,len do
+			local child = t[n];
+			if child.name then
+				self(child, buf, self, _xml_escape, t.attr.xmlns);
+			else
+				t_insert(buf, _xml_escape(child));
+			end
+		end
+		t_insert(buf, "</"..name..">");
+	end
+end
+
+return {
+	enable = function ()
+		local stanza_mt = require "util.stanza".stanza_mt;
+		stanza_mt._unsorted_tostring = stanza_mt.__tostring;
+		function stanza_mt.__tostring(t)
+			local buf = {};
+			_dostring(t, buf, _dostring, xml_escape, nil);
+			return t_concat(buf);
+		end;
+	end;
+	disable = function ()
+		local stanza_mt = require "util.stanza".stanza_mt;
+		if stanza_mt._unsorted_tostring then
+			stanza_mt.__tostring = stanza_mt._unsorted_tostring;
+		end
+	end;
+};
+

mercurial