-
Notifications
You must be signed in to change notification settings - Fork 1
/
luamml-xmlwriter.lua
62 lines (59 loc) · 1.78 KB
/
luamml-xmlwriter.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
-- FIXME: Not sure yet if this will be needed
local function escape_name(name)
return name
end
local escapes = {
['"'] = """,
['<'] = "<",
['>'] = ">",
['&'] = "&",
}
local function escape_text(text)
return string.gsub(string.gsub(tostring(text), '["<>&]', escapes), '[\x00-\x08\x0B\x0C\x0E-\x1F]', function(x)
return string.format('^^%02x', string.byte(x))
end)
end
local attrs = {}
local function write_elem(tree, indent)
if not tree[0] then print('ERR', require'inspect'(tree)) end
local escaped_name = escape_name(assert(tree[0]))
local i = 0
for attr, val in next, tree do if type(attr) == 'string' then
if not string.find(attr, ':', 1, true) then
-- if string.byte(attr) ~= 0x3A then
i = i + 1
attrs[i] = string.format(' %s="%s"', escape_name(attr), escape_text(val))
end
end end
table.sort(attrs)
local out = string.format('%s<%s%s', indent or '', escaped_name, table.concat(attrs))
for j = 1, i do attrs[j] = nil end
if not tree[1] then
return out .. '/>'
end
out = out .. '>'
-- Never indent the content if it's purely text.
if #tree == 1 and type(tree[1]) == 'string' then
indent = nil
end
local inner_indent = indent and indent .. ' '
local is_string
for _, elem in ipairs(tree) do
if type(elem) == 'string' then
if inner_indent and not is_string then
out = out .. inner_indent
end
out = out .. escape_text(elem)
is_string = true
else
out = out .. write_elem(elem, inner_indent)
is_string = nil
end
end
if indent then out = out .. indent end
return out .. '</' .. escaped_name .. '>'
end
return function(element, indent, version)
return (version == '11' and '<?xml version="1.1"?>' or '') ..
write_elem(element, indent and '\n' or nil)
end