src/lxp/totable.lua

changeset 37
233463804681
equal deleted inserted replaced
36:4a61f00ee916 37:233463804681
1 -- See Copyright Notice in license.html
2 -- Based on Luiz Henrique de Figueiredo's lxml:
3 -- http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/#lxml
4
5 local lxp = require "lxp"
6
7 local table = require"table"
8 local tinsert, tremove = table.insert, table.remove
9 local assert, pairs, tostring, type = assert, pairs, tostring, type
10
11 -- auxiliary functions -------------------------------------------------------
12 local function starttag (p, tag, attr)
13 local stack = p:getcallbacks().stack
14 local newelement = {[0] = tag}
15 for i = 1, #attr do
16 local attrname = attr[i]
17 local attrvalue = attr[attrname]
18 newelement[attrname] = attrvalue
19 end
20 tinsert(stack, newelement)
21 end
22
23 local function endtag (p, tag)
24 local stack = p:getcallbacks().stack
25 local element = tremove(stack)
26 assert(element[0] == tag, "Error while closing element: table[0] should be `"..tostring(tag).."' but is `"..tostring(element[0]).."'")
27 local level = #stack
28 tinsert(stack[level], element)
29 end
30
31 local function text (p, txt)
32 local stack = p:getcallbacks().stack
33 local element = stack[#stack]
34 local n = #element
35 if type(element[n]) == "string" and n > 0 then
36 element[n] = element[n] .. txt
37 else
38 tinsert(element, txt)
39 end
40 end
41
42 -- main function -------------------------------------------------------------
43 local function parse (o)
44 local c = {
45 StartElement = starttag,
46 EndElement = endtag,
47 CharacterData = text,
48 _nonstrict = true,
49 stack = {{}},
50 }
51 local p = lxp.new(c)
52 if type(o) == "string" then
53 local status, err, line, col, pos = p:parse(o)
54 if not status then return nil, err, line, col, pos end
55 else
56 for l in pairs(o) do
57 local status, err, line, col, pos = p:parse(l)
58 if not status then return nil, err, line, col, pos end
59 end
60 end
61 local status, err, line, col, pos = p:parse() -- close document
62 if not status then return nil, err, line, col, pos end
63 p:close()
64 return c.stack[1][1]
65 end
66
67 -- utility functions ---------------------------------------------------------
68 local function compact (t) -- remove empty entries
69 local n = 0
70 for i = 1, #t do
71 local v = t[i]
72 if v then
73 n = n+1
74 if n ~= i then
75 t[n] = v
76 t[i] = nil
77 end
78 else
79 t[i] = nil
80 end
81 end
82 end
83
84 local function clean (t) -- remove empty strings
85 for i = 1, #t do
86 local v = t[i]
87 local tv = type(v)
88 if tv == "table" then
89 clean (v)
90 elseif tv == "string" and v:match"^%s*$" then
91 t[i] = false
92 end
93 end
94 compact (t)
95 end
96
97 local function torecord (t) -- move 1-value subtables to table entries
98 for i = 1, #t do
99 local v = t[i]
100 if type(v) == "table" then
101 if #v == 1 and type(v[1]) == "string" and t[v[0]] == nil then
102 t[v[0]] = v[1]
103 t[i] = false
104 else
105 torecord (v)
106 end
107 end
108 end
109 compact (t)
110 end
111
112 return {
113 clean = clean,
114 compact = compact,
115 parse = parse,
116 torecord = torecord,
117 }

mercurial