Thu, 23 Mar 2023 15:12:30 +0000
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 = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" }; |
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 |