Output Lua Table To Html File |
|
-- dontspamme_samlie@yahoo.com
-- Converts Lua table to HTML output in table.html file function tohtml(x) ret = tohtml_table(x,1) writefile("table.html", ret) os.execute("table.html") return(ret) end -- Saves a string to file function writefile(filename, value) if (value) then local file = io.open(filename,"w+") file:write(value) file:close() end end -- Flattens a table to html output function tohtml_table(x, table_level) local k, s, tcolor local html_colors = { "#339900","#33CC00","#669900","#666600","#FF3300", "#FFCC00","#FFFF00","#CCFFCC","#CCCCFF","#CC66FF", "#339900","#33CC00","#669900","#666600","#FF3300", "#FFCC00","#FFFF00","#CCFFCC","#CCCCFF","#CC66FF" } local lineout = {} local tablefound = false if type(x) == "table" then s = "" k = 1 local i, v = next(x) while i do if (type(v) == "table") then if (table_level<10) then lineout[k] = "<b>" .. flat(i) .. "</b>".. tohtml_table(v, table_level + 1) else lineout[k] = "<b>MAXIMUM LEVEL BREACHED</b>" end tablefound = true else lineout[k] = flat(i) .. "=" .. tohtml_table(v) end k = k + 1 i, v = next(x, i) end for k,line in ipairs(lineout) do if (tablefound) then s = s .. "<tr><td>" .. line .. "</td></tr>\n" else s = s .. "<td>" .. line .. "</td>\n" end end if not (tablefound) then s = "<table border='1' bgcolor='#FFFFCC' cellpadding='5' cellspacing='0'>" .. "<tr>" .. s .. "</tr></table>\n" else tcolor = html_colors[table_level] s = "<table border='3' bgcolor='"..tcolor.."' cellpadding='10' cellspacing='0'>" .. s .. "</table>\n" end return s end if type(x) == "function" then return "FUNC" end if type(x) == "file" then return "FILE" end return tostring(x) end -- Flattens a table to string function flat(x) return toflat(x,1) end -- Flattens a table to string function toflat(x, tlevel) local s tlevel = tlevel + 1 if type(x) == "table" then s = "{" local i, v = next(x) while i do if (tlevel < 15) then s = s .. i .. "=" .. toflat(v, tlevel) else s = s .. i .. "={#}" end i, v = next(x, i) if i then s = s .. ", " end end return s .. "}\n" end if type(x) == "function" then return "FUNC" end if type(x) == "file" then return "FILE" end return tostring(x) end
Here is a more advanced implementation, with expand/collapsing and handling cycles. (See warning in comments before use.)
-- Example dumping Lua tables to HTML for debugging. -- -- Warning: not complete or well tested. This is only intended -- as an example/starting point. Clean it up if used in production. -- -- (c) 2008 David Manura (2008-12) -- Licensed under the same terms as Lua (MIT license). local coroutine = coroutine local next = next local pairs = pairs local string = string local tostring = tostring local type = type local _G = _G local format = string.format -- Escape string to make suitable for embedding in HTML. local function htmlize(s) s = s:gsub('&', '&') s = s:gsub('<', '<') s = s:gsub('>', '>') return s end -- iterator function for table pairs. -- hash part, then array part. -- used for display. local function table_pairs(t) local keys = {} for k in pairs(t) do keys[#keys+1] = k end table.sort(keys, function(a,b) if type(a) == 'number' and type(b) == 'string' then return false elseif type(a) == 'string' and type(b) == 'number' then return true else return a < b end end) local i = 0 return function() i = i + 1 local k = keys[i] if k then return k, t[k] end end end -- Serialize object o. Writes one or more substrings to function append. local function obj_serialize(o, append) if type(o) == 'table' then append('{') for k,v in table_pairs(o) do append('[') obj_serialize(k, append) append(']=[') obj_serialize(v, append) append('];') end append('}') elseif type(o) == 'string' then append(string.format('%q', o)) else append(tostring(o)) end end -- Returns serialization of o, not exceeding maxlen characters. local function obj_tostring_short(o, maxlen) local s = '' local function append(ss) s = s .. ss if #s > maxlen then s = s:sub(1,maxlen) .. '...' coroutine.yield() end end local f = coroutine.wrap(obj_serialize) f(o, append) return s end local function analyze_tree(o) local ids = {} local current_id = 0 local count = {} local from = {} local function analyze_tree_helper(o) if type(o) == 'table' then if count[o] then count[o] = count[o] + 1 else count[o] = 1 current_id = current_id + 1 ids[o] = current_id local this_id = current_id for k,v in pairs(o) do analyze_tree_helper(k) analyze_tree_helper(v) if type(k) == 'table' then from[k] = from[k] or {}; from[k][o] = this_id .. '.' .. ids[k] end if type(v) == 'table' then from[v] = from[v] or {}; from[v][o] = this_id .. '.' .. (ids[k] or tostring(k)) end end end end end analyze_tree_helper(o) for k,v in pairs(count) do if v == 1 then count[k] = nil end end return ids, count, from end local header = [[ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <title>FIX</title> <style type="text/css"> .table {margin-left:1em; border: 1px solid black} .table_row {border: 1px solid black} </style> <script type="text/javascript"><!-- function toggle(id) { if (document.getElementById) { var ele = document.getElementById(id); if (ele && ele.style) { ele.style.display = ele.style.display == 'none' ? '' : 'none'; } } } function show_node(ele) { if (ele.style) { ele.style.display = ''; if (ele.parentNode) show_node(ele.parentNode); } } function show(id) { if (document.getElementById) { var ele = document.getElementById(id); if (ele) show_node(ele); } } //--></script> </head> <body> ]] local footer = [[</body></html>]] -- Writes HTML representations of object o as one or more strings to -- function output. local function object_to_html(o, output) local ids, count, from = analyze_tree(o) local output_html local function output_header_html(o) if type(o) == 'table' then output(format('<a name="id%s"></a>', ids[o])) local is_empty = next(o) == nil output(is_empty and '(empty)' or '<a href="javascript:toggle(\'id' .. ids[o] .. '\')">[+]</a>') output(format([[Table ID %s]], ids[o])) output(type(o.tag) == 'string' and ' [Tag=' .. o.tag .. ']' or '') output(' ') output(htmlize(obj_tostring_short(o, 40))) elseif type(o) == 'string' then output(htmlize(string.format('%q', o))) else output(htmlize(tostring(o))) end end local function output_body_html(o) if type(o) == 'table' then output(format('<div class="table" style="display:none" id="id%s">\n', ids[o])) -- xref if from[o] and next(from[o]) and next(from[o], next(from[o])) then output('<div>Referenced from: ') for _,from_id in pairs(from[o]) do output(format([[ <a onclick="show('id%s')" href="#id%s">%s</a> ]], from_id, from_id, from_id)) end output('</div>') end -- key/values for k,v in table_pairs(o) do local function prepare_output(oo) local f, is_long if count[oo] then f = function() output(format([[<a onclick="show('id%s')" href="#id%s">(see %s)</a>]], ids[oo],ids[oo],ids[oo])) end elseif type(oo) ~= 'table' then f = function() output_header_html(oo) end else f = function() output_header_html(oo) end is_long = true end return f, is_long end local kf, klong = prepare_output(k) local vf, vlong = prepare_output(v) local field_id = ids[o] .. '.' .. (ids[k] or tostring(k)) output(format([[<a name="id%s"></a>]], field_id)) output(format('<div class="table_row" id="id%s">\n', field_id)) kf() output('=') vf() if vlong then output_body_html(v) end output('</div>') end output('</div>\n') end end --local function output_html(o) output('<div>') output_header_html(o) output('</div>') output_body_html(o) end output(header) output_html(o) for oo in pairs(count) do if oo ~= o then output_html(oo) end end output(footer) end -- example usage local function dump(obj) object_to_html(obj, function(s) io.stdout:write(s) end) end dump(_G) -- metalua example --[[ package.path = package.path .. ';/luaanalyze/lib/?.lua' require "lexer" require "gg" require "mlp_lexer" require "mlp_misc" require "mlp_table" require "mlp_meta" require "mlp_expr" require "mlp_stat" require "mlp_ext" mlc = {} -- make gg happy local mlp = assert(_G.mlp) local function string_to_ast(src, filename) filename = filename or '(string)' local lx = mlp.lexer:newstream (src, filename) local ast = mlp.chunk(lx) return ast end local src_file = assert(io.open ('mydump.lua', 'r')) local src = src_file:read '*a'; src_file:close() local ast = string_to_ast(src, src_filename) local function remove_lineinfo(o) if type(o) == 'table' then o.lineinfo = nil for k,v in pairs(o) do remove_lineinfo(k) remove_lineinfo(v) end end end remove_lineinfo(ast) dump(ast) --]]