JSON Lua API
概述
ljson 模块提供了在 Lua 中操作 JSON 数据的功能。该模块通过 userdata 的方式封装 JSON 对象,避免了 JSON 对象作为 Lua table 存储时键值无序的问题,同时保持了键的插入顺序。
加载模块
local ljson = require("ljson")
主要特性
- 编码与解码:
encode/decode在 Lua 值和 JSON 字符串之间双向转换 - 有序 JSON 对象:
json_object_ordered_decode返回保持插入顺序的 userdata 对象 - 格式化输出:
json_object_ordered_encode_pretty/dump_pretty输出带缩进的易读 JSON - 空表行为控制:
encode_empty_table_as_object全局切换空 table 的 JSON 表示({}或[]) - 深拷贝与比较:
json_object_copy创建独立副本,json_object_is_equal进行深度相等比较 - 元方法支持:
__index/__newindex/__len/__pairs让 JSON userdata 像 Lua table 一样操作
接口说明
序列化和反序列化
encode(value)
将 Lua 值编码为 JSON 字符串(紧凑格式)。
参数:
value: Lua 值(nil、boolean、number、string、table)
返回值: JSON 字符串(string)
说明:
- 将 Lua 值转换为紧凑格式的 JSON 字符串(无缩进和换行)
- 支持所有 Lua 基础类型:nil、boolean、number、string、table
- table 会根据内容自动识别为对象或数组:
- 如果是连续整数索引从 1 开始,则编码为数组
- 否则编码为对象
- 空 table 默认编码为空数组
[],可通过encode_empty_table_as_object修改 - 支持嵌套的 table,会递归转换
- 对象的键会按照字符串顺序排序
示例:
local ljson = require("ljson")
-- 编码基本类型
print(ljson.encode(nil)) -- "null"
print(ljson.encode(true)) -- "true"
print(ljson.encode(42)) -- "42"
print(ljson.encode("hello")) -- "\"hello\""
-- 编码数组
local arr = {1, 2, 3, "four"}
print(ljson.encode(arr)) -- "[1,2,3,"four"]"
-- 编码对象
local obj = {name = "Alice", age = 30}
print(ljson.encode(obj)) -- "{\"age\":30,\"name\":\"Alice\"}"
-- 编码嵌套结构
local nested = {
user = "Alice",
profile = {
age = 30,
email = "alice@example.com"
},
tags = {"tag1", "tag2"}
}
print(ljson.encode(nested))
-- {"profile":{"age":30,"email":"alice@example.com"},"tags":["tag1","tag2"],"user":"Alice"}
decode(json_string)
将 JSON 字符串解码为 Lua 值。
参数:
json_string: JSON 字符串
返回值: Lua 值(table、null lightuserdata、boolean、number、string)
说明:
- 将 JSON 字符串解析为 Lua 值
- JSON 对象转换为 Lua table
- JSON 数组转换为 Lua 数组 table
- JSON null 转换为空指针 lightuserdata;它可保存在 table 中并重新编码为 null
- 递归转换所有嵌套对象和数组
示例:
local ljson = require("ljson")
-- 解码 JSON 字符串
local json_str = '{"name":"Alice","age":30}'
local obj = ljson.decode(json_str)
print(obj.name) -- "Alice"
print(obj.age) -- 30
-- 解码数组
local arr_str = '[1,2,3,"four"]'
local arr = ljson.decode(arr_str)
for i = 1, #arr do
print(arr[i])
end
-- 解码嵌套结构
local nested_str = '{"user":"Alice","profile":{"age":30}}'
local nested = ljson.decode(nested_str)
print(nested.profile.age) -- 30
json_object_ordered_decode(json_string)
将 JSON 字符串解码为 JSON 对象(userdata),保持键的插入顺序。
参数:
json_string: JSON 字符串
返回值: JSON 对象或数组(userdata)
说明:
- 将 JSON 字符串解析为 JsonValue 对象(userdata)
- 与
decode不同,本函数返回 userdata 而不是普通 table - userdata 会保持 JSON 对象中键的插入顺序
- 适合需要保持键顺序或需要使用 JSON 对象元方法的场景
- 返回的 userdata 支持所有 JSON 对象的元方法(__index、__newindex、__len、__pairs 等)
示例:
local ljson = require("ljson")
-- 解码 JSON 字符串为 userdata
local json_str = '{"name":"Alice","age":30,"email":"alice@example.com"}'
local json_obj = ljson.json_object_ordered_decode(json_str)
-- 通过元方法访问元素
print(json_obj.name) -- "Alice"
print(json_obj.age) -- 30
-- 获取所有键(保持插入顺序)
local keys = ljson.json_object_get_keys(json_obj)
for i, k in ipairs(keys) do
print("键", i, ":", k)
end
-- 输出顺序:name, age, email(保持 JSON 中的顺序)
-- 遍历对象(保持键的顺序)
for k, v in pairs(json_obj) do
local val = ljson.json_object_to_table(v)
print("键:", k, "值:", val)
end
-- 转换为普通 table
local tbl = ljson.json_object_to_table(json_obj)
print(tbl.name) -- "Alice"
json_object_ordered_encode(json_value)
将 JSON 对象(userdata)编码为 JSON 字符串(紧凑格式)。
参数:
json_value: JSON 对象或数组(userdata)
返回值: JSON 字符串(string)
说明:
- 将 JsonValue userdata 编码为紧凑格式的 JSON 字符串(无缩进和换行)
- 与
encode不同,本函数接受 userdata 而不是普通 Lua 值 - 适合需要将
json_object_ordered_decode或json_object_from_table创建的 userdata 转换为 JSON 字符串的场景 - 对象的键会按照字符串顺序排序
- 支持嵌套对象和数组的递归编码
示例:
local ljson = require("ljson")
-- 从 userdata 编码为 JSON 字符串
local json_obj = ljson.json_object_from_table({
name = "Alice",
age = 30,
email = "alice@example.com"
})
local json_str = ljson.json_object_ordered_encode(json_obj)
print(json_str)
-- {"age":30,"email":"alice@example.com","name":"Alice"}
-- 解码后再编码
local json_str2 = '{"name":"Bob","age":25}'
local json_obj2 = ljson.json_object_ordered_decode(json_str2)
local encoded = ljson.json_object_ordered_encode(json_obj2)
print(encoded)
-- {"age":25,"name":"Bob"}
-- 编码数组
local arr = ljson.json_object_from_table({1, 2, 3, "four"})
local arr_str = ljson.json_object_ordered_encode(arr)
print(arr_str)
-- [1,2,3,"four"]
-- 编码嵌套结构
local nested = ljson.json_object_from_table({
user = "Alice",
profile = {
age = 30,
email = "alice@example.com"
},
tags = {"tag1", "tag2"}
})
local nested_str = ljson.json_object_ordered_encode(nested)
print(nested_str)
-- {"profile":{"age":30,"email":"alice@example.com"},"tags":["tag1","tag2"],"user":"Alice"}
json_object_ordered_encode_pretty(json_value)
将 JSON 对象(userdata)编码为格式化的 JSON 字符串(带缩进)。
参数:
json_value: JSON 对象或数组(userdata)
返回值: JSON 字符串(string)
说明:
- 将 JsonValue userdata 编码为格式化的 JSON 字符串(带缩进和换行)
- 与
json_object_ordered_encode不同,本函数输出易读的格式化 JSON - 与
encode不同,本函数接受 userdata 而不是普通 Lua 值 - 适合需要将
json_object_ordered_decode或json_object_from_table创建的 userdata 转换为易读的 JSON 字符串的场景 - 对象的键会按照字符串顺序排序
- 支持嵌套对象和数组的递归编码
- 输出的 JSON 格式易读,适合需要人工查看的场景
示例:
local ljson = require("ljson")
-- 从 userdata 编码为格式化的 JSON 字符串
local json_obj = ljson.json_object_from_table({
name = "Alice",
age = 30,
email = "alice@example.com"
})
local json_str = ljson.json_object_ordered_encode_pretty(json_obj)
print(json_str)
-- 输出:
-- {
-- "age": 30,
-- "email": "alice@example.com",
-- "name": "Alice"
-- }
-- 解码后再编码(格式化输出)
local json_str2 = '{"name":"Bob","age":25}'
local json_obj2 = ljson.json_object_ordered_decode(json_str2)
local encoded = ljson.json_object_ordered_encode_pretty(json_obj2)
print(encoded)
-- 输出:
-- {
-- "age": 25,
-- "name": "Bob"
-- }
-- 编码数组(格式化输出)
local arr = ljson.json_object_from_table({1, 2, 3, "four"})
local arr_str = ljson.json_object_ordered_encode_pretty(arr)
print(arr_str)
-- 输出:
-- [
-- 1,
-- 2,
-- 3,
-- "four"
-- ]
-- 编码嵌套结构(格式化输出)
local nested = ljson.json_object_from_table({
user = "Alice",
profile = {
age = 30,
email = "alice@example.com"
},
tags = {"tag1", "tag2"}
})
local nested_str = ljson.json_object_ordered_encode_pretty(nested)
print(nested_str)
-- 输出:
-- {
-- "profile": {
-- "age": 30,
-- "email": "alice@example.com"
-- },
-- "tags": [
-- "tag1",
-- "tag2"
-- ],
-- "user": "Alice"
-- }
dump(value, file_path)
将 Lua 值编码为 JSON 字符串并写入文件(紧凑格式)。
参数:
value: Lua 值(nil、boolean、number、string、table)file_path: 目标文件路径(string)
返回值: boolean(成功返回 true,失败返回 false)
说明:
- 将 Lua 值转换为紧凑格式的 JSON 字符串(无缩进和换行)
- 将 JSON 字符串写入指定文件
- 如果文件已存在,会覆盖原文件
- 支持所有 Lua 基础类型和嵌套结构
- 编码规则与
encode相同
示例:
local ljson = require("ljson")
-- 编码基本类型到文件
local success = ljson.dump("hello", "/tmp/output.json")
print(success) -- true
-- 编码对象到文件
local obj = {name = "Alice", age = 30}
ljson.dump(obj, "/tmp/user.json")
-- 编码嵌套结构到文件
local nested = {
user = "Alice",
profile = {
age = 30,
email = "alice@example.com"
},
tags = {"tag1", "tag2"}
}
ljson.dump(nested, "/tmp/data.json")
dump_pretty(value, file_path)
将 Lua 值编码为格式化的 JSON 字符串并写入文件(带缩进)。
参数:
value: Lua 值(nil、boolean、number、string、table)file_path: 目标文件路径(string)
返回值: boolean(成功返回 true,失败返回 false)
说明:
- 将 Lua 值转换为格式化的 JSON 字符串(带缩进和换行)
- 将 JSON 字符串写入指定文件
- 如果文件已存在,会覆盖原文件
- 支持所有 Lua 基础类型和嵌套结构
- 编码规则与
encode相同 - 输出的 JSON 格式易读,适合需要人工查看的场景
示例:
local ljson = require("ljson")
-- 编码对象到文件(格式化输出)
local obj = {
name = "Alice",
age = 30,
tags = {"tag1", "tag2"}
}
ljson.dump_pretty(obj, "/tmp/user_pretty.json")
-- 输出文件内容:
-- {
-- "age": 30,
-- "name": "Alice",
-- "tags": [
-- "tag1",
-- "tag2"
-- ]
-- }
-- 编码嵌套结构到文件(格式化输出)
local nested = {
user = "Alice",
profile = {
age = 30,
email = "alice@example.com"
}
}
ljson.dump_pretty(nested, "/tmp/data_pretty.json")
json_object_dump(json_value, file_path)
将 JSON 对象(userdata)编码为 JSON 字符串并写入文件(紧凑格式)。
参数:
json_value: JSON 对象或数组(userdata)file_path: 目标文件路径(string)
返回值: boolean(成功返回 true,失败返回 false)
说明:
- 将 JsonValue userdata 转换为紧凑格式的 JSON 字符串(无缩进和换行)
- 将 JSON 字符串写入指定文件
- 如果文件已存在,会覆盖原文件
- 与
dump不同,本函数接受 userdata 而不是普通 Lua 值 - 适合需要将
json_object_ordered_decode或json_object_from_table创建的 userdata 保存到文件的场景 - 支持嵌套对象和数组的递归编码
- 对象的键会按照字符串顺序排序
示例:
local ljson = require("ljson")
-- 将 userdata 保存到文件(紧凑格式)
local json_obj = ljson.json_object_from_table({
name = "Alice",
age = 30,
email = "alice@example.com"
})
local success = ljson.json_object_dump(json_obj, "/tmp/user.json")
print(success) -- true
-- 解码 JSON 字符串后保存到文件
local json_str = '{"name":"Bob","age":25}'
local json_obj2 = ljson.json_object_ordered_decode(json_str)
ljson.json_object_dump(json_obj2, "/tmp/user2.json")
-- 将数组保存到文件(紧凑格式)
local arr = ljson.json_object_from_table({1, 2, 3, "four"})
ljson.json_object_dump(arr, "/tmp/array.json")
-- 将嵌套结构保存到文件(紧凑格式)
local nested = ljson.json_object_from_table({
user = "Alice",
profile = {
age = 30,
email = "alice@example.com"
},
tags = {"tag1", "tag2"}
})
ljson.json_object_dump(nested, "/tmp/data.json")
json_object_dump_pretty(json_value, file_path)
将 JSON 对象(userdata)编码为格式化的 JSON 字符串并写入文件(带缩进)。
参数:
json_value: JSON 对象或数组(userdata)file_path: 目标文件路径(string)
返回值: boolean(成功返回 true,失败返回 false)
说明:
- 将 JsonValue userdata 转换为格式化的 JSON 字符串(带缩进和换行)
- 将 JSON 字符串写入指定文件
- 如果文件已存在,会覆盖原文件
- 与
dump_pretty不同,本函数接受 userdata 而不是普通 Lua 值 - 适合需要将
json_object_ordered_decode或json_object_from_table创建的 userdata 以易读格式保存到文件的场景 - 支持嵌套对象和数组的递归编码
- 对象的键会按照字符串顺序排序
- 输出的 JSON 格式易读,适合需要人工查看的场景
示例:
local ljson = require("ljson")
-- 将 userdata 保存到文件(格式化输出)
local json_obj = ljson.json_object_from_table({
name = "Alice",
age = 30,
email = "alice@example.com"
})
local success = ljson.json_object_dump_pretty(json_obj, "/tmp/user_pretty.json")
print(success) -- true
-- 输出文件内容:
-- {
-- "age": 30,
-- "email": "alice@example.com",
-- "name": "Alice"
-- }
-- 解码 JSON 字符串后保存到文件(格式化输出)
local json_str = '{"name":"Bob","age":25}'
local json_obj2 = ljson.json_object_ordered_decode(json_str)
ljson.json_object_dump_pretty(json_obj2, "/tmp/user2_pretty.json")
-- 输出文件内容:
-- {
-- "age": 25,
-- "name": "Bob"
-- }
-- 将数组保存到文件(格式化输出)
local arr = ljson.json_object_from_table({1, 2, 3, "four"})
ljson.json_object_dump_pretty(arr, "/tmp/array_pretty.json")
-- 输出文件内容:
-- [
-- 1,
-- 2,
-- 3,
-- "four"
-- ]
-- 将嵌套结构保存到文件(格式化输出)
local nested = ljson.json_object_from_table({
user = "Alice",
profile = {
age = 30,
email = "alice@example.com"
},
tags = {"tag1", "tag2"}
})
ljson.json_object_dump_pretty(nested, "/tmp/data_pretty.json")
-- 输出文件内容:
-- {
-- "profile": {
-- "age": 30,
-- "email": "alice@example.com"
-- },
-- "tags": [
-- "tag1",
-- "tag2"
-- ],
-- "user": "Alice"
-- }
encode_empty_table_as_object(boolean)
设置空 table 编码为 JSON 对象还是数组。
参数:
boolean: 布尔值(true 表示空 table 编码为对象{},false 表示空 table 编码为数组[])
返回值: 无
说明:
- 控制空 table 的 JSON 编码方式
- 默认情况下(false),空 table 编码为空数组
[] - 设置为 true 时,空 table 编码为空对象
{} - 此设置是全局的,会影响后续所有
encode、dump、json_object_from_table等操作
示例:
local ljson = require("ljson")
-- 默认行为:空 table 编码为数组
print(ljson.encode({})) -- "[]"
-- 修改为空 table 编码为对象
ljson.encode_empty_table_as_object(true)
print(ljson.encode({})) -- "{}"
-- 恢复默认行为
ljson.encode_empty_table_as_object(false)
print(ljson.encode({})) -- "[]"
创建 JSON 对象和数组
json_object_new_object()
创建一个新的空 JSON 对象。
返回值: JSON 对象(userdata)
示例:
local obj = ljson.json_object_new_object()
obj.name = "Alice"
obj.age = 30
json_object_new_array()
创建一个新的空 JSON 数组。
返回值: JSON 数组(userdata)
示例:
local arr = ljson.json_object_new_array()
arr[1] = 100
arr[2] = 200
类型转换
json_object_from_table(table)
从 Lua table 创建 JSON 对象或数组。
参数:
table: Lua table,可以是对象(键值对)或数组(连续整数索引)
返回值: JSON 对象或数组(userdata)
说明:
- 如果 table 是数组(连续整数索引从 1 开始),则创建 JSON 数组
- 如果 table 是对象(键值对),则创建 JSON 对象
- 对象中的键会按照字符串顺序排序,以保证稳定的顺序
- 支持嵌套的 table,会递归转换
示例:
-- 创建对象
local obj = ljson.json_object_from_table({
name = "Alice",
age = 30,
tags = {"tag1", "tag2"}
})
-- 创建数组
local arr = ljson.json_object_from_table({1, 2, 3, "four", true})
json_object_to_table(json_value)
将 JSON 对象或数组转换为 Lua table。
参数:
json_value: JSON 对象或数组(userdata)
返回值: Lua table(普通 table,不包含 userdata)
说明:
- 只接受 userdata(json_object)作为参数,如果传入普通的 Lua table 会报错
- 递归转换所有嵌套对象和数组
- 返回的 table 中所有值都是普通的 Lua 类型(nil、boolean、number、string、table),不包含 userdata
- 返回的是转换时的快照,不会自动反映 userdata 的后续变化
示例:
local json_obj = ljson.json_object_from_table({
name = "Alice",
age = 30,
profile = {
email = "alice@example.com"
}
})
-- 转换为 table
local tbl = ljson.json_object_to_table(json_obj)
print(tbl.name) -- "Alice"
print(tbl.profile.email) -- "alice@example.com"
-- 注意:tbl.profile 已经是普通 table,不是 userdata
assert(type(tbl.profile) == "table")
assert(type(tbl.profile) ~= "userdata")
类型检查
json_object_is_object(json_value)
检查 JSON 值是否为对象。
参数:
json_value: JSON 值(userdata)
返回值: boolean
示例:
local obj = ljson.json_object_new_object()
assert(ljson.json_object_is_object(obj) == true)
json_object_is_array(json_value)
检查 JSON 值是否为数组。
参数:
json_value: JSON 值(userdata)
返回值: boolean
示例:
local arr = ljson.json_object_new_array()
assert(ljson.json_object_is_array(arr) == true)
对象操作
json_object_get_keys(json_object)
获取 JSON 对象的所有键,按照插入顺序返回。
参数:
json_object: JSON 对象(userdata)
返回值: Lua 数组,包含所有键(字符串)
示例:
local obj = ljson.json_object_from_table({first = 1, second = 2, third = 3})
local keys = ljson.json_object_get_keys(obj)
-- keys = {"first", "second", "third"}
for i, k in ipairs(keys) do
print("键", i, ":", k)
end
json_object_is_equal(json1, json2)
比较两个 JSON 值是否相等。
参数:
json1: 第一个 JSON 值(userdata 或 Lua 值)json2: 第二个 JSON 值(userdata 或 Lua 值)
返回值: boolean
说明:
- 支持深度比较,包括嵌套对象和数组
- 如果参数不是 userdata,会自动转换为 JSON 值进行比较
示例:
local obj1 = ljson.json_object_from_table({a = 1, b = 2})
local obj2 = ljson.json_object_from_table({a = 1, b = 2})
assert(ljson.json_object_is_equal(obj1, obj2) == true)
json_object_copy(json_value)
复制 JSON 对象或数组,创建独立的副本。
参数:
json_value: JSON 对象或数组(userdata)
返回值: JSON 对象或数组的副本(userdata)
说明:
- 创建深拷贝,修改副本不会影响原始对象
- 支持嵌套对象和数组的递归复制
示例:
local original = ljson.json_object_from_table({
name = "Alice",
data = {value = 100}
})
local copied = ljson.json_object_copy(original)
copied.name = "Bob"
copied.data.value = 200
-- 原始对象未被修改
local orig_tbl = ljson.json_object_to_table(original)
assert(orig_tbl.name == "Alice")
assert(orig_tbl.data.value == 100)
底层操作(高级用法)
to_raw(json_value)
获取 JSON 值的底层 C 指针(userdata)。
参数:
json_value: JSON 值(userdata)
返回值: 底层指针(userdata)
说明: 仅用于高级场景,一般不需要使用。
new_from_raw(raw_ptr)
从底层 C 指针创建 JSON 值。
参数:
raw_ptr: 底层指针(userdata)
返回值: JSON 值(userdata)
说明: 仅用于高级场景,一般不需要使用。
元方法
JSON 对象和数组支持以下 Lua 元方法,可以通过类似操作普通 table 的方式来操作 JSON 对象。
__index - 访问元素
支持通过 obj[key] 或 arr[index] 的方式访问 JSON 对象和数组的元素。
对象访问:
local obj = ljson.json_object_from_table({name = "Alice", age = 30})
print(obj.name) -- "Alice"
print(obj["age"]) -- 30
数组访问:
local arr = ljson.json_object_from_table({10, 20, 30})
print(arr[1]) -- 10
print(arr[2]) -- 20
__newindex - 设置元素
支持通过 obj[key] = value 或 arr[index] = value 的方式设置 JSON 对象和数组的元素。
对象设置:
local obj = ljson.json_object_new_object()
obj.name = "Alice"
obj.age = 30
obj.nested = {key = "value"} -- 支持直接设置 Lua table,会自动转换
数组设置:
local arr = ljson.json_object_new_array()
arr[1] = 100
arr[2] = 200
arr[3] = 300
-- 修改已存在的元素
arr[2] = 250
-- 在末尾添加新元素
arr[4] = 400
-- 索引超出范围时会自动扩展数组(用 null 填充)
arr[10] = 1000 -- 索引 5-9 会被填充为 null
__len - 获取长度
支持通过 #obj 或 #arr 的方式获取 JSON 对象或数组的长度。
对象长度:
local obj = ljson.json_object_from_table({a = 1, b = 2, c = 3})
print(#obj) -- 3(键值对的数量)
数组长度:
local arr = ljson.json_object_from_table({10, 20, 30})
print(#arr) -- 3(元素的数量)
__pairs - 遍历对象
支持通过 for k, v in pairs(obj) 的方式遍历 JSON 对象,键的顺序与插入顺序一致。
local obj = ljson.json_object_from_table({first = 1, second = 2, third = 3})
for k, v in pairs(obj) do
local val = ljson.json_object_to_table(v)
print("键:", k, "值:", val)
end
-- 输出顺序:first, second, third(保持插入顺序)
注意: 遍历时返回的值 v 是 userdata,如果需要获取实际值,需要使用 json_object_to_table(v) 转换。
__gc - 垃圾回收
自动管理 JSON 对象的生命周期,当 Lua 对象被垃圾回收时,会自动释放底层的 JSON 资源。
使用示例
示例 1:创建和操作 JSON 对象
local ljson = require("ljson")
-- 创建对象
local obj = ljson.json_object_new_object()
obj.name = "Alice"
obj.age = 30
obj.email = "alice@example.com"
-- 访问元素
print(obj.name) -- "Alice"
print(obj.age) -- 30
-- 获取所有键
local keys = ljson.json_object_get_keys(obj)
for i, k in ipairs(keys) do
print("键", i, ":", k)
end
-- 转换为 table
local tbl = ljson.json_object_to_table(obj)
print(tbl.name) -- "Alice"
示例 2:创建和操作 JSON 数组
local ljson = require("ljson")
-- 创建数组
local arr = ljson.json_object_new_array()
arr[1] = 100
arr[2] = 200
arr[3] = 300
-- 访问元素
print(arr[1]) -- 100
print(arr[2]) -- 200
-- 获取长度
print(#arr) -- 3
-- 修改元素
arr[2] = 250
-- 转换为 table
local tbl = ljson.json_object_to_table(arr)
for i = 1, #tbl do
print("元素", i, ":", tbl[i])
end
示例 3:嵌套结构
local ljson = require("ljson")
-- 创建嵌套对象
local obj = ljson.json_object_from_table({
name = "Alice",
profile = {
age = 30,
email = "alice@example.com",
address = {
city = "Beijing",
country = "China"
}
},
tags = {"tag1", "tag2", "tag3"}
})
-- 访问嵌套属性
print(obj.profile.email) -- "alice@example.com"
print(obj.profile.address.city) -- "Beijing"
-- 转换为 table(递归转换)
local tbl = ljson.json_object_to_table(obj)
print(tbl.profile.email) -- "alice@example.com"
-- tbl.profile 已经是普通 table,不是 userdata
assert(type(tbl.profile) == "table")
assert(type(tbl.profile) ~= "userdata")
示例 4:遍历对象(保持键的顺序)
local ljson = require("ljson")
-- 创建对象
local obj = ljson.json_object_from_table({
first = 1,
second = 2,
third = 3
})
-- 遍历对象(键的顺序与插入顺序一致)
for k, v in pairs(obj) do
local val = ljson.json_object_to_table(v)
print("键:", k, "值:", val)
end
-- 输出:
-- 键: first 值: 1
-- 键: second 值: 2
-- 键: third 值: 3
示例 5:复制对象
local ljson = require("ljson")
-- 创建原始对象
local original = ljson.json_object_from_table({
name = "Alice",
data = {value = 100}
})
-- 复制对象
local copied = ljson.json_object_copy(original)
-- 修改副本
copied.name = "Bob"
copied.data.value = 200
-- 验证原始对象未被修改
local orig_tbl = ljson.json_object_to_table(original)
assert(orig_tbl.name == "Alice")
assert(orig_tbl.data.value == 100)
-- 验证副本已修改
local copy_tbl = ljson.json_object_to_table(copied)
assert(copy_tbl.name == "Bob")
assert(copy_tbl.data.value == 200)
示例 6:比较对象
local ljson = require("ljson")
-- 创建两个相同的对象
local obj1 = ljson.json_object_from_table({a = 1, b = 2, c = 3})
local obj2 = ljson.json_object_from_table({a = 1, b = 2, c = 3})
-- 比较对象
assert(ljson.json_object_is_equal(obj1, obj2) == true)
-- 修改其中一个对象
obj2.c = 4
assert(ljson.json_object_is_equal(obj1, obj2) == false)
注意事项
1. 键的顺序
- JSON 对象中的键会按照字符串顺序排序,以保证稳定的顺序
- 使用
pairs遍历时,键的顺序与插入顺序一致(实际上是按字符串顺序)
2. json_object_to_table 的行为
json_object_to_table返回的是转换时的快照,不会自动反映 userdata 的后续变化- 如果需要获取最新状态,需要重新调用
json_object_to_table - 转换后的 table 中所有嵌套对象和数组都是普通 table,不包含 userdata
示例:
local obj = ljson.json_object_new_object()
obj.key1 = "value1"
-- 转换为 table
local tbl = ljson.json_object_to_table(obj)
assert(tbl.key1 == "value1")
-- 修改 userdata
obj.key2 = "value2"
-- 旧的 table 不会自动更新
assert(tbl.key2 == nil) -- 旧 table 中没有 key2
-- 需要重新转换以获取最新状态
local tbl2 = ljson.json_object_to_table(obj)
assert(tbl2.key2 == "value2") -- 新 table 中有 key2
3. 数组中的 nil 值
- Lua 的
#操作符在遇到nil值时会停止计数 - 如果 JSON 数组中包含
null值,转换为 Lua table 后,#操作符可能无法正确计算长度 - 建议直接通过索引访问元素,而不是依赖
#操作符
示例:
local arr = ljson.json_object_from_table({1, 2, 3, nil, 5})
local tbl = ljson.json_object_to_table(arr)
-- #tbl 会返回 3(在 nil 处停止),而不是 5
-- 应该直接通过索引访问
assert(tbl[1] == 1)
assert(tbl[2] == 2)
assert(tbl[3] == 3)
assert(tbl[4] == nil)
assert(tbl[5] == 5)
4. 类型检查
json_object_is_object和json_object_is_array只接受 userdata 参数- 如果传入已转换的普通 table,这些函数会报错
- 在调用这些函数之前,确保参数是 userdata
示例:
local obj = ljson.json_object_from_table({name = "Alice"})
assert(ljson.json_object_is_object(obj) == true) -- 正确
local tbl = ljson.json_object_to_table(obj)
-- ljson.json_object_is_object(tbl) -- 错误!tbl 是普通 table,不是 userdata
5. 性能考虑
json_object_from_table和json_object_to_table会进行深度转换,对于大型嵌套结构可能有性能开销- 如果需要频繁访问,建议保持 userdata 形式,而不是频繁转换
6. 错误处理
- 所有接口在出错时会抛出 Lua 错误
- 建议使用
pcall包装可能出错的操作
示例:
local success, err = pcall(function()
ljson.json_object_to_table({key = "value"}) -- 错误:只接受 userdata
end)
if not success then
print("错误:", err)
end
最佳实践
✅ 使用 json_object_to_table 统一数据出口
当需要在 Lua 逻辑中处理 JSON 数据时,尽早转换为普通 table 以获得完整的 Lua 表操作能力:
-- ✅ 尽早转为 table
local json_obj = ljson.json_object_ordered_decode(json_str)
local tbl = ljson.json_object_to_table(json_obj)
-- tbl 现在是普通 Lua table,可以直接传递、修改
return process_data(tbl)
✅ 用 dump_pretty 保存配置文件
保存供人工查看的 JSON 文件时,使用 dump_pretty 或 json_object_dump_pretty:
-- ✅ 格式化写入,便于人工检查
ljson.dump_pretty(config_table, "/etc/app/config.json")
❌ 不要将 json_object_to_table 的返回值误当 userdata 操作
json_object_to_table 返回普通 table,不能再使用 json_object_* 函数:
-- ❌ 错误:tbl 是 table,不能传给 json_object_is_object
local tbl = ljson.json_object_to_table(json_obj)
if ljson.json_object_is_object(tbl) then -- 报错!
...
end
❌ 避免频繁在 table 和 userdata 之间来回转换
在大循环中反复调用 json_object_from_table 和 json_object_to_table 会产生大量临时对象和递归开销:
-- ❌ 循环中频繁转换
for _, item in ipairs(big_list) do
local obj = ljson.json_object_from_table(item)
local jstr = ljson.json_object_ordered_encode(obj)
local tbl = ljson.json_object_to_table(obj)
end
-- ✅ 一次转换,复用结果
local obj = ljson.json_object_from_table(data)
local jstr = ljson.json_object_ordered_encode(obj)