29

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?

3
  • 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? Commented Jul 23, 2014 at 11:06
  • 1
    lua-users.org/wiki/JsonModules Commented Jul 23, 2014 at 12:03
  • you're probably after LuaJSON Commented Jul 30, 2014 at 8:15

3 Answers 3

19

maybe lua-cjson is 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)
Sign up to request clarification or add additional context in comments.

1 Comment

the link to lua-cjson is broken for me - maybe its better to link to luarocks.org/modules/openresty/lua-cjson?
16

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

2 Comments

How to use json.parse function?
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?
11

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.

4 Comments

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)
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.
This answer contains a mistake. There are two rocks with similar names: One is the afforementioned pure lua implementation lua-json, here you need to require("JSON") though. The other is the C-implementation lua-json where you would require("json"). So the above answer should actually require("JSON").
Thanks for the follow up. It was written long time ago. In that time, it was like that. Now, i corrected my answer. I already linked json-lua GitHub repo page. Everyone please take a look there, before blindly copy paste.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.