scansion/ordered_serializer.lua

Thu, 23 Mar 2023 15:12:30 +0000

author
Matthew Wild <mwild1@gmail.com>
date
Thu, 23 Mar 2023 15:12:30 +0000
changeset 174
662bd8c5ae28
child 178
e547ddf8b64d
permissions
-rw-r--r--

Serialize XML in a consistent order by default

This overrides all XML serialization to emit attributes in an ordered form, so
the XML will match across multiple runs. This can be useful for comparing
different runs, or even two stanzas printed in the same run (e.g. if there is
a mismatch).

174
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1 local s_find, s_gsub, s_match = string.find, string.gsub, string.match;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
2 local t_concat, t_insert = table.concat, table.insert;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
3
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
4 local pairs = require "util.iterators".sorted_pairs;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
5
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
6 local escape_table = { ["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;" };
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
7 local function xml_escape(str) return (s_gsub(str, "['&<>\"]", escape_table)); end
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
8
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
9 local function _dostring(t, buf, self, _xml_escape, parentns)
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
10 local nsid = 0;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
11 local name = t.name
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
12 t_insert(buf, "<"..name);
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
13 for k, v in pairs(t.attr) do
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
14 if s_find(k, "\1", 1, true) then
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
15 local ns, attrk = s_match(k, "^([^\1]*)\1?(.*)$");
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
16 nsid = nsid + 1;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
17 t_insert(buf, " xmlns:ns"..nsid.."='".._xml_escape(ns).."' ".."ns"..nsid..":"..attrk.."='".._xml_escape(v).."'");
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
18 elseif not(k == "xmlns" and v == parentns) then
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
19 t_insert(buf, " "..k.."='".._xml_escape(v).."'");
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
20 end
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
21 end
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
22 local len = #t;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
23 if len == 0 then
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
24 t_insert(buf, "/>");
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
25 else
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
26 t_insert(buf, ">");
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
27 for n=1,len do
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
28 local child = t[n];
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
29 if child.name then
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
30 self(child, buf, self, _xml_escape, t.attr.xmlns);
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
31 else
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
32 t_insert(buf, _xml_escape(child));
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
33 end
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
34 end
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
35 t_insert(buf, "</"..name..">");
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
36 end
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
37 end
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
38
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
39 return {
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
40 enable = function ()
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
41 local stanza_mt = require "util.stanza".stanza_mt;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
42 stanza_mt._unsorted_tostring = stanza_mt.__tostring;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
43 function stanza_mt.__tostring(t)
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
44 local buf = {};
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
45 _dostring(t, buf, _dostring, xml_escape, nil);
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
46 return t_concat(buf);
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
47 end;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
48 end;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
49 disable = function ()
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
50 local stanza_mt = require "util.stanza".stanza_mt;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
51 if stanza_mt._unsorted_tostring then
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
52 stanza_mt.__tostring = stanza_mt._unsorted_tostring;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
53 end
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
54 end;
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
55 };
662bd8c5ae28 Serialize XML in a consistent order by default
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
56

mercurial