25

I need to convert a Json String to a table data structure in Lua. I am using the following code.

local json = require "json"

local t = { 
    ["name1"] = "value1",
    ["name2"] = { 1, false, true, 23.54, "a \021 string" },
    name3 = json.null
}

local encode = json.encode (t)
print (encode)  --> {"name1":"value1","name3":null,"name2":[1,false,true,23.54,"a \u0015 string"]}

local decode = json.decode( encode )

But when I run the script, I get the following errors,

    no field package.preload['json']
    no file '/usr/local/share/lua/5.2/json.lua'
    no file '/usr/local/share/lua/5.2/json/init.lua'
    no file '/usr/local/lib/lua/5.2/json.lua'
    no file '/usr/local/lib/lua/5.2/json/init.lua'
    no file './json.lua'
    no file '/usr/local/lib/lua/5.2/json.so'
    no file '/usr/local/lib/lua/5.2/loadall.so'
    no file './json.so'

So how to convert my json string to lua table?

user3213851
  • 1,068
  • 2
  • 12
  • 24
  • 7
    The problem has nothing to do with coding. You have to install a "json" Lua library into your system. That could be as simple as plopping down "./json.lua" or you might get it via a package manager. There are several choices available. Which one are you using and how are you installing it and on which operating system? – Tom Blodget Jul 23 '14 at 11:06
  • 1
    http://lua-users.org/wiki/JsonModules – moteus Jul 23 '14 at 12:03
  • you're probably after [LuaJSON](https://github.com/harningt/luajson/blob/master/rockspecs/luajson-1.3.1-1.rockspec) – Dmitry Ledentsov Jul 30 '14 at 08:15

3 Answers3

19

maybe lua-cjsonis your friend:

install e.g. through luarocks:

$sudo luarocks install lua-cjson

then in lua:

local json = require('cjson')
local tab = json.decode(json_string)
json_string = json.encode(tab)
lipp
  • 5,586
  • 1
  • 21
  • 32
13

https://gist.github.com/tylerneylon/59f4bcf316be525b30ab

I found pure lua script file to parse json data (just one file).

local json = {}


-- Internal functions.

local function kind_of(obj)
  if type(obj) ~= 'table' then return type(obj) end
  local i = 1
  for _ in pairs(obj) do
    if obj[i] ~= nil then i = i + 1 else return 'table' end
  end
  if i == 1 then return 'table' else return 'array' end
end

local function escape_str(s)
  local in_char  = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'}
  local out_char = {'\\', '"', '/',  'b',  'f',  'n',  'r',  't'}
  for i, c in ipairs(in_char) do
    s = s:gsub(c, '\\' .. out_char[i])
  end
  return s
end

-- Returns pos, did_find; there are two cases:
-- 1. Delimiter found: pos = pos after leading space + delim; did_find = true.
-- 2. Delimiter not found: pos = pos after leading space;     did_find = false.
-- This throws an error if err_if_missing is true and the delim is not found.
local function skip_delim(str, pos, delim, err_if_missing)
  pos = pos + #str:match('^%s*', pos)
  if str:sub(pos, pos) ~= delim then
    if err_if_missing then
      error('Expected ' .. delim .. ' near position ' .. pos)
    end
    return pos, false
  end
  return pos + 1, true
end

-- Expects the given pos to be the first character after the opening quote.
-- Returns val, pos; the returned pos is after the closing quote character.
local function parse_str_val(str, pos, val)
  val = val or ''
  local early_end_error = 'End of input found while parsing string.'
  if pos > #str then error(early_end_error) end
  local c = str:sub(pos, pos)
  if c == '"'  then return val, pos + 1 end
  if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end
  -- We must have a \ character.
  local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'}
  local nextc = str:sub(pos + 1, pos + 1)
  if not nextc then error(early_end_error) end
  return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc))
end

-- Returns val, pos; the returned pos is after the number's final character.
local function parse_num_val(str, pos)
  local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos)
  local val = tonumber(num_str)
  if not val then error('Error parsing number at position ' .. pos .. '.') end
  return val, pos + #num_str
end


-- Public values and functions.

function json.stringify(obj, as_key)
  local s = {}  -- We'll build the string as an array of strings to be concatenated.
  local kind = kind_of(obj)  -- This is 'array' if it's an array or type(obj) otherwise.
  if kind == 'array' then
    if as_key then error('Can\'t encode array as key.') end
    s[#s + 1] = '['
    for i, val in ipairs(obj) do
      if i > 1 then s[#s + 1] = ', ' end
      s[#s + 1] = json.stringify(val)
    end
    s[#s + 1] = ']'
  elseif kind == 'table' then
    if as_key then error('Can\'t encode table as key.') end
    s[#s + 1] = '{'
    for k, v in pairs(obj) do
      if #s > 1 then s[#s + 1] = ', ' end
      s[#s + 1] = json.stringify(k, true)
      s[#s + 1] = ':'
      s[#s + 1] = json.stringify(v)
    end
    s[#s + 1] = '}'
  elseif kind == 'string' then
    return '"' .. escape_str(obj) .. '"'
  elseif kind == 'number' then
    if as_key then return '"' .. tostring(obj) .. '"' end
    return tostring(obj)
  elseif kind == 'boolean' then
    return tostring(obj)
  elseif kind == 'nil' then
    return 'null'
  else
    error('Unjsonifiable type: ' .. kind .. '.')
  end
  return table.concat(s)
end

json.null = {}  -- This is a one-off table to represent the null value.

function json.parse(str, pos, end_delim)
  pos = pos or 1
  if pos > #str then error('Reached unexpected end of input.') end
  local pos = pos + #str:match('^%s*', pos)  -- Skip whitespace.
  local first = str:sub(pos, pos)
  if first == '{' then  -- Parse an object.
    local obj, key, delim_found = {}, true, true
    pos = pos + 1
    while true do
      key, pos = json.parse(str, pos, '}')
      if key == nil then return obj, pos end
      if not delim_found then error('Comma missing between object items.') end
      pos = skip_delim(str, pos, ':', true)  -- true -> error if missing.
      obj[key], pos = json.parse(str, pos)
      pos, delim_found = skip_delim(str, pos, ',')
    end
  elseif first == '[' then  -- Parse an array.
    local arr, val, delim_found = {}, true, true
    pos = pos + 1
    while true do
      val, pos = json.parse(str, pos, ']')
      if val == nil then return arr, pos end
      if not delim_found then error('Comma missing between array items.') end
      arr[#arr + 1] = val
      pos, delim_found = skip_delim(str, pos, ',')
    end
  elseif first == '"' then  -- Parse a string.
    return parse_str_val(str, pos + 1)
  elseif first == '-' or first:match('%d') then  -- Parse a number.
    return parse_num_val(str, pos)
  elseif first == end_delim then  -- End of an object or array.
    return nil, pos + 1
  else  -- Parse true, false, or null.
    local literals = {['true'] = true, ['false'] = false, ['null'] = json.null}
    for lit_str, lit_val in pairs(literals) do
      local lit_end = pos + #lit_str - 1
      if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end
    end
    local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10)
    error('Invalid json syntax starting at ' .. pos_info_str)
  end
end

return json
Anantha Raju C
  • 1,780
  • 12
  • 25
  • 35
livem
  • 141
  • 1
  • 5
  • 2
    How to use json.parse function? – Apogee Apr 19 '20 at 07:22
  • I've tried `require "json" test = { one="8" , two="2" } print( test["one"] ) a=json.stringify( test) print(a)` and it returns error `attempt to index a nil value (global 'json')` what's wrong? – superbem Apr 19 '22 at 19:11
10

You can use json-lua. A pure lua implementation of json. First install json-lua using Luarocks. luarocks install json-lua . Then Use this code :

local json = require "json"

local t = { 
    ["name1"] = "value1",
    ["name2"] = { 1, false, true, 23.54, "a \021 string" },
    name3 = json.null
}

local encode = json:encode (t)
print (encode)  --> {"name1":"value1","name3":null,"name2":[1,false,true,23.54,"a \u0015 string"]}

local decode = json:decode( encode )

Tested & Verified on win 7 64 bit with lua 5.1. lua-cjson is fine, but it is not a pure lua rock. So, it's installation will not be easier to you.

Banee Ishaque K
  • 531
  • 8
  • 21
  • Sadly, json:decode doesn't work in my case. Tested with a valid json string on Ubuntu with Lua 5.2, it just returns `lua: /usr/share/lua/5.2/json/util.lua:55: bad argument #1 to 'pairs' (table expected, got string)` – Oxy Synth Mar 17 '18 at 12:05
  • There are several json-lua implementations, some require dot instead of colon, so `json.decode(encode)`. This is for example the case with the one in Ubuntu repo. – Michal Sylwester Jul 04 '19 at 14:55