2 local t_insert = table.insert;
3 local st = require "util.stanza";
4 local lxp = require "lxp";
5 local setmetatable = setmetatable;
8 local s_gsub = string.gsub;
14 local function process_stanza(stanza, ops)
16 for key, val in pairs(stanza.attr) do
17 if val:match("{[^}]*}") then
18 t_insert(ops, {stanza.attr, key, val});
24 local child = stanza[i];
26 process_stanza(child, ops);
27 elseif child:match("^{[^}]*}$") then -- text
28 t_insert(ops, {stanza, i, child:match("^{([^}]*)}$"), true});
29 elseif child:match("{[^}]*}") then -- text
30 t_insert(ops, {stanza, i, child});
36 local parse_xml = (function()
38 ["http://www.w3.org/XML/1998/namespace"] = "xml";
40 local ns_separator = "\1";
41 local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$";
44 local stanza = st.stanza("root");
45 function handler:StartElement(tagname, attr)
46 local curr_ns,name = tagname:match(ns_pattern);
48 curr_ns, name = "", curr_ns;
56 local ns, nm = k:match(ns_pattern);
60 attr[ns..":"..nm] = attr[k];
65 stanza:tag(name, attr);
67 function handler:CharacterData(data)
68 data = data:gsub("^%s*", ""):gsub("%s*$", "");
71 function handler:EndElement(tagname)
74 local parser = lxp.new(handler, "\1");
75 local ok, err, line, col = parser:parse(xml);
76 if ok then ok, err, line, col = parser:parse(); end
79 return stanza.tags[1];
81 return ok, err.." (line "..line..", col "..col..")";
86 local stanza_mt = st.stanza_mt;
87 local function fast_st_clone(stanza, lookup)
88 local stanza_attr = stanza.attr;
89 local stanza_tags = stanza.tags;
90 local tags, attr = {}, {};
91 local clone = { name = stanza.name, attr = attr, tags = tags, last_add = {} };
92 for k,v in pairs(stanza_attr) do attr[k] = v; end
93 lookup[stanza_attr] = attr;
94 for i=1,#stanza_tags do
95 local child = stanza_tags[i];
96 local new = fast_st_clone(child, lookup);
101 local child = stanza[i];
102 clone[i] = lookup[child] or child;
104 return setmetatable(clone, stanza_mt);
107 local function create_template(text)
108 local stanza, err = parse_xml(text);
109 if not stanza then error(err); end
111 process_stanza(stanza, ops);
115 function template.apply(data)
116 local newstanza = fast_st_clone(stanza, lookup);
119 local t, k, v, g = op[1], op[2], op[3], op[4];
121 lookup[t][k] = data[v];
123 lookup[t][k] = s_gsub(v, "{([^}]*)}", data);
131 local templates = setmetatable({}, { __mode = 'k' });
132 return function(text)
133 local template = templates[text];
135 template = create_template(text);
136 templates[text] = template;