Module:Data to Table
| Main | Documentation | Usage |
This module implements {{Data to Table}}.
local p = {}
local CleanTT = require('Module:tt').CleanTT
local lib = require('Module:Feature')
local ne = lib.isNotEmpty
local block = false
-- Check if the entry is the first on the level
local first = {true, true, true}
-- Check if the entry is right after the end of a deeper level
local previous = {false, false, false}
-- Escape characters for Lua strings
local function clean(txt)
return txt
:gsub('\\', '\\\\')
:gsub('\'', '\\\'')
end
function p.main(frame)
local info = {}
local dataKeys = {}
local rawKeys = {}
-- Parse DPL data
if frame.args.info then
if ne(frame.args.cleanTT) then
frame.args.info = CleanTT(frame.args.info)
end
info = lib.parseTemplateFormat(
frame.args.info,
';;',
'$$$',
'=='
)
else
return ''
end
-- Parse keys
if frame.args.keys then
dataKeys = p.ParseKeys(frame.args.keys)
end
-- Parse unquoted/raw keys
if frame.args.unquoted then
rawKeys = p.ParseKeys(frame.args.unquoted)
end
-- Block formatting
if ne(frame.args.block) then
block = true
end
local sortkey = frame.args.sortkey or 'page'
local subtable = frame.args.subtable
-- JSON mode
local jsonMode = tostring(frame.args.json) == '1'
-- Constant value mode
-- If |value=day is supplied, every page gets that value.
local constantValue = frame.args.value
local valueUnquoted = false
if constantValue ~= nil then
for _, rawKey in ipairs(rawKeys) do
if rawKey == 'value' then
valueUnquoted = true
break
end
end
end
-- Check whether a key should be output as raw Lua
local function isUnquotedKey(key)
for _, rawKey in ipairs(rawKeys) do
if rawKey == key then
return true
end
end
return false
end
-- ============================================================
-- JSON OUTPUT
-- ============================================================
if jsonMode then
local jsonEntries = {}
-- Sort entries using the same sorting logic as normal output
local sortedEntries = {}
for _, entry in lib.spairs(
info,
function(tVal, a, b)
if sortkey == 'INPUT' then
return a < b
else
return (tVal[a][sortkey] or '') < (tVal[b][sortkey] or '')
end
end
) do
if ne(entry.page) then
jsonEntries[#jsonEntries + 1] = entry.page
end
end
-- Encode the array as valid JSON
local jsonText = mw.text.jsonEncode(jsonEntries)
local output = frame:extensionTag(
'syntaxhighlight',
jsonText,
{
lang = 'json',
copy = ''
}
)
-- Copy button
if frame.args.copy then
output = require('Module:CopyText')._main({
output,
frame.args.copy,
'Copy JSON'
})
end
return output
end
-- ============================================================
-- LUA OUTPUT
-- ============================================================
-- Build result
local result = mw.html.create()
:wikitext('return {\n')
for _, entry in lib.spairs(
info,
function(tVal, a, b)
if sortkey == 'INPUT' then
return a < b
else
return (tVal[a][sortkey] or '') < (tVal[b][sortkey] or '')
end
end
) do
if ne(entry.page) then
entry.page = clean(entry.page)
-- Constant value mode:
-- |value=day produces ['Page'] = 'day'
if constantValue ~= nil and #dataKeys == 0 then
local value
if valueUnquoted then
value = clean(constantValue)
else
value = '\'' .. clean(constantValue) .. '\''
end
result:wikitext(
'\t[\'',
entry.page,
'\'] = ',
value,
',\n'
)
-- No data keys: output page as a simple string
elseif #dataKeys == 0 then
result:wikitext(
'\t\'',
entry.page,
'\',\n'
)
else
-- Reset formatting state for every entry
first = {true, true, true}
previous = {false, false, false}
local valid = false
local values = mw.html.create()
-- Entry name
values:wikitext(
'\t[\'',
entry.page,
'\'] = {'
)
-- Build entry
local function parseLevels(K, level)
level = level or 1
if type(K) == 'string' then
valid = true
-- Use the value if present.
-- BuildEntry handles missing values.
values:node(
p.BuildEntry(
entry[K],
K,
level,
subtable,
isUnquotedKey(K)
)
)
elseif type(K) == 'table' then
level = level + 1
for _, K2 in ipairs(K) do
parseLevels(K2, level)
end
values:wikitext(
'\n',
string.rep('\t', level - 1),
'},'
)
end
end
parseLevels(dataKeys, 1)
-- Return table if there is valid data
if valid then
values:wikitext('\n')
result:node(values)
else
result:wikitext(
'\t\'',
entry.page,
'\',\n'
)
end
end
end
end
result:wikitext('}')
-- Wrap output in syntaxhighlight
local luaText = tostring(result)
-- Decode HTML entities introduced by mw.html
luaText = mw.text.decode(luaText)
local output = frame:extensionTag(
'syntaxhighlight',
luaText,
{
lang = 'lua',
copy = ''
}
)
-- Copy button
if frame.args.copy then
output = require('Module:CopyText')._main({
output,
frame.args.copy,
'Copy Table'
})
end
return output
end
-- ================================================================
-- FORMAT DATA
-- ================================================================
function p.BuildEntry(value, key, level, subtable, unquoted)
level = level or 1
local container = mw.html.create()
-- Default missing values
if value == nil or value == '' then
if key == 'number' then
value = '0'
unquoted = true
else
value = ''
unquoted = false
end
end
-- Format value
if subtable and value ~= '' and value:find(subtable) then
value = lib.split(
clean(value),
subtable
)
value = '{ \'' ..
table.concat(value, '\', \'') ..
' }'
elseif unquoted and value ~= '' then
-- Raw Lua value
value = clean(value)
else
-- String value
value = '\'' ..
clean(value) ..
'\''
end
-- Format key as ['key']
local formattedKey =
'[\'' .. clean(key) .. '\']'
-- First item on this level
if first[level] then
container:wikitext(
'\n',
string.rep('\t', level),
formattedKey,
' = ',
value,
','
)
first[level] = false
if level > 2 then
first[2] = false
end
if level > 1 then
first[1] = false
end
-- Subsequent item on this level
else
container:wikitext(
'\n',
string.rep('\t', level),
formattedKey,
' = ',
value,
','
)
previous[level] = false
end
return container
end
-- ================================================================
-- PARSE DATA KEYS INTO SPECIFIED LEVELS
-- ================================================================
function p.ParseKeys(keys)
keys = lib.split(keys, ';;')
for i, key in pairs(keys) do
if key:find('//') then
local keys2 = lib.split(key, '//')
for i2, key2 in pairs(keys2) do
if key2:find('@@') then
keys2[i2] = lib.split(key, '@@')
end
end
keys[i] = keys2
end
end
return keys
end
return p