Модуль:JSON
Көрүнүш
Бул модулда Lua маанилерин JSON маанилерине (UTF-8 коддолгон Lua саптарында) айландыруу үчүн кээ бир пайдалуу ыкмалар сунушталат.
Тилекке каршы, Луанын берилиштер модели JSONдикинен бир аз айырмаланат, андыктан кандайдыр бир Lua маанисин алып, JSON маанисин кайтарган жалпы функцияны жазуу мүмкүн эмес, ар дайым "туура иш кылып". Тескерисинче, кээ бир баалуулуктарды такыр эле айландыруу мүмкүн эмес, ал эми башка баалуулуктардын бир нече эквиваленттүү эмес өкүлчүлүктөрү бар.
Айырмачылыктар төмөнкүлөр:
- Луанын JSON аналогу жок үч түрү бар, атап айтканда function, userdata жана thread, ошондуктан бул модулда ал түрлөрдүн маанилери колдоого алынбайт.
- Луанын "меттаблицалар" концепциясы JSONда аналогу жок, ошондуктан бул модуль метатаблицаларды толугу менен этибарга албайт.
- Луанын number түрү, Scribuntoдо ишке ашырылгандай, кош тактыктагы калкыма чекиттик маанилерден турат, ал эми JSONдун сан түрү ондук көрсөтүүлөрдөн турат. (Жана JSON берилиштерин акыркы алуучу, кыязы, маанилерди кандайдыр бир калкыма чекиттик белгиге айландырышы мүмкүн.) Бул бүтүн сандардан тышкары, жалпысынан маанилердин так конвертацияланышын күтө албайсыз дегенди билдирет. (Жана бүтүн сандар менен да, сиз ±109 же башка диапазондо кемчиликсиз конвертацияны гана күтө аласыз.) Андан тышкары, Луанын эч кандай JSON аналогдору жок бир нече сандык маанилери бар, тактап айтканда, оң чексиздик, терс чексиздик жана "сан эмес" маанилери; ошондуктан, бул модул бул баалуулуктарды колдобойт.
- Луанын string түрү сегиз биттик байт саптарын билдирет, ал эми JSONдун *сап* түрү Юникод символдорунун саптарын билдирет. Бул модулда Lua саптары жарактуу UTF-8 ырааттуулугу болушун талап кылат.
- Луа бир гана table тибиндеги ыктыярдуу nil эмес маанилерден ыктыярдуу nil эмес маанилерге чейин бир гана картага ээ болсо, JSON өзүнчө "'массивге" ээ. ' жана объект түрлөрү, мында массив {0,1,…,n} бүтүн сандардын жыйындысынан ыктыярдуу маанилерге, ал эми объект ыктыярдуу саптардан ыктыярдуу маанилерге карталарды түзөт. Натыйжада, бул модул [TBD]
(Эскертүү: жогорудагы айырмачылыктардын толук тизмеси аракети, бирок мен кээ бирлерин өткөрүп жиберген болушум толук мүмкүн.)
local m_str_utils = require("Module:string utilities")
local m_table = require("Module:table")
local codepoint = m_str_utils.codepoint
local gsub = m_str_utils.gsub
local export = {}
-- Given a finite real number x, returns a string containing its JSON
-- representation, with enough precision that it *should* round-trip correctly
-- (depending on the well-behavedness of the system on the other end).
function export.json_fromNumber(x)
if type(x) ~= "number" then
error('Not of type "number": ' .. x .. " (" .. type(x) .. ")")
end
if x ~= x or x == math.huge or x == -math.huge then
error("Not a finite real number: " .. x)
end
return string.format("%.17g", x)
end
-- This function makes an effort to convert an arbitrary Lua value to a string
-- containing a JSON representation of it. It's not intended to be very robust,
-- but may be useful for prototyping.
function export.toJSON(val, opts)
opts = opts or {}
local function converter(val)
if type(val) == "nil" then
return "null"
elseif type(val) == "boolean" then
return val and "true" or "false"
elseif type(val) == "number" then
return export.json_fromNumber(val)
elseif type(val) == "string" then
return export.json_fromString(val)
elseif type(val) == "table" then
-- If the table has a toJSON member function, call that.
if val.toJSON then
return val:toJSON()
else
return export.json_fromTable(val, converter, opts)
end
else
error("Unsupported type: " .. type(val))
end
end
return converter(val)
end
local escape_char_map = {
["\\"] = "\\\\",
["\""] = "\\\"",
["\b"] = "\\b",
["\f"] = "\\f",
["\n"] = "\\n",
["\r"] = "\\r",
["\t"] = "\\t",
}
local function escape_char(c)
return escape_char_map[c] or string.format("\\u%04X", codepoint(c))
end
-- Given a string, escapes any illegal characters and wraps it in double-quotes.
-- Raises an error if the string is not valid UTF-8.
function export.json_fromString(s)
if type(s) ~= "string" or not mw.ustring.isutf8(s) then
error("Not a valid UTF-8 string: " .. s)
end
-- U+2029 (LINE SEPARATOR, \226\128\168 in UTF-8)
-- and U+2028 (PARAGRAPH SEPARATOR, \226\128\169 in UTF-8) are allowed
-- in JSON, but must be escaped for compatibility with JavaScript.
s = gsub(s, '[\\"%c\226\128\168\226\128\169]', escape_char)
return '"' .. s .. '"'
end
-- Given a table, treats it as an array and assembles its values in the form
-- "[ v1, v2, v3 ]". Optionally takes a function to JSONify the values before
-- assembly; if that function is omitted, then the values should already be
-- strings containing valid JSON data.
function export.json_arrayFromTable(val, converter, opts)
converter = converter or function (x) return x end
-- If `val` comes from mw.loadData() then #val is always 0, so deep copy to avoid this.
val = m_table.deepcopy(val)
local ret = {}
for i = 1, #val do
elem = converter(val[i])
if elem ~= nil then
table.insert(ret, elem)
end
end
if #ret == 0 then
return "[]"
end
return opts and opts.compress and "[" .. table.concat(ret, ",") .. "]" or
"[ " .. table.concat(ret, ", ") .. " ]"
end
-- Given a table whose keys are all strings, assembles its keys and values in
-- the form '{ "k1": v1, "k2": v2, "k3": v3 }'. Optionally takes a function to
-- JSONify the values before assembly; if that function is omitted, then the
-- values should already be strings containing valid JSON data. (The keys, by
-- contrast, should just be regular Lua strings; they will be passed to this
-- module's json_fromString.)
function export.json_fromTable(val, converter, opts)
converter = converter or function (x) return x end
local as_object = {}
local string_key = false
for key, value in pairs(val) do
value = converter(value)
if type(key) ~= "number" then
string_key = true
end
if value ~= nil then
key = export.json_fromString(tostring(key))
table.insert(as_object, key .. (opts and opts.compress and ":" or " : ") .. value)
end
end
if string_key then
return "{" .. table.concat(as_object, opts and opts.compress and "," or ", ") .. "}"
else
return export.json_arrayFromTable(val, converter, opts)
end
end
return export