1 -- luacheck: ignore 213/i
2 local stanza_mt
= require
"util.stanza".stanza_mt
;
3 local setmetatable
= setmetatable
;
7 local envload
= require
"util.envload".envload
;
9 local t_remove
= table.remove;
10 local parse_xml
= require
"util.xml".parse
;
15 local function trim_xml(stanza
)
17 local child
= stanza
[i
];
21 child
= child
:gsub("^%s*", ""):gsub("%s*$", "");
23 if child
== "" then t_remove(stanza
, i
); end
28 local function create_string_string(str
)
29 str
= ("%q"):format(str
);
30 str
= str
:gsub("{([^}]*)}", function(s
)
31 return '"..(data["'..s
..'"]or"").."';
35 local function create_attr_string(attr
, xmlns
)
37 for name
,value
in pairs(attr
) do
38 if name
~= "xmlns" or value
~= xmlns
then
39 str
= str
..("[%q]=%s;"):format(name
, create_string_string(value
));
44 local function create_clone_string(stanza
, lookup
, xmlns
)
45 if not lookup
[stanza
] then
46 local s
= ('setmetatable({name=%q,attr=%s,tags={'):format(stanza
.name
, create_attr_string(stanza
.attr
, xmlns
));
48 for i
,tag in ipairs(stanza
.tags
) do
49 s
= s
..create_clone_string(tag, lookup
, stanza
.attr
.xmlns
)..";";
53 for i
,child
in ipairs(stanza
) do
55 s
= s
..create_clone_string(child
, lookup
, stanza
.attr
.xmlns
)..";";
57 s
= s
..create_string_string(child
)..";"
60 s
= s
..'}, stanza_mt)';
61 s
= s
:gsub('%.%.""', ""):gsub('([=;])""%.%.', "%1"):gsub(';"";', ";"); -- strip empty strings
62 local n
= #lookup
+ 1;
64 lookup
[stanza
] = "_"..n
;
66 return lookup
[stanza
];
68 local function create_cloner(stanza
, chunkname
)
70 local name
= create_clone_string(stanza
, lookup
, "");
71 local src
= "local setmetatable,stanza_mt=...;return function(data)";
73 src
= src
.."local _"..i
.."="..lookup
[i
]..";";
75 src
= src
.."return "..name
..";end";
76 local f
,err
= envload(src
, chunkname
);
77 if not f
then error(err
); end
78 return f(setmetatable
, stanza_mt
);
81 local template_mt
= { __tostring
= function(t
) return t
.name
end };
82 local function create_template(templates
, text
)
83 local stanza
, err
= parse_xml(text
);
84 if not stanza
then error(err
); end
87 local info
= debug
.getinfo(3, "Sl");
88 info
= info
and ("template(%s:%d)"):format(info
.short_src
:match("[^\\/]*$"), info
.currentline
) or "template(unknown)";
90 local template
= setmetatable({ apply
= create_cloner(stanza
, info
), name
= info
, text
= text
}, template_mt
);
91 templates
[text
] = template
;
95 local templates
= setmetatable({}, { __mode
= 'k', __index
= create_template
});
97 return templates
[text
];