--- /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 = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" }; +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; +}; +