如何将树形结构数据库数据转为单块JSON键值对(无额外库)
问题描述
我的数据库返回如下树形结构数据:
'((7 "vince" "vince1@test.com" "space" "no value" 1) (8 "vince" "vince2@test.com" "place" "no value" 1) (9 "Smith" "Smith@gmail.com" "now" "no value" 1))
其中第二列为名字,第三列为邮箱。我希望将其转换为包含所有记录的单个JSON数组,但尝试的方法只返回多个独立的JSON块,遇到了困难。
我已尝试的方法:
- 编写函数提取单个列表项中的姓名和邮箱:
(defun get-name-&-emails-db1 (lst) (if (null lst) nil (let* ((name (second lst)) (email (third lst))) (cl-json:encode-json-to-string `((:name . ,name)(:email . ,email))))))
- 遍历数据集:
(mapcar #'get-name-&-emails-db1 (return-data-tree))
现在需要解决的是:如何生成包含所有记录的单个JSON块,优先希望不使用任何额外库实现。
解决方案
你现在的问题出在:mapcar会给每个列表项单独调用JSON编码函数,所以得到的是一堆独立的JSON字符串,而不是把所有记录合并成一个完整的JSON数组。
方法一:不依赖第三方库实现
直接手动拼接JSON字符串就行,步骤很简单:
- 遍历所有数据,把每个条目的姓名、邮箱转换成
{"name": "...", "email": "..."}格式的字符串; - 把这些字符串用逗号连起来,再套上数组的
[]括号。
代码实现:
(defun data-to-json (data) (let ((entries (mapcar (lambda (item) (format nil "{\"name\": \"~a\", \"email\": \"~a\"}" (second item) (third item))) data))) (format nil "[~{~a~^, ~}]" entries))) ;; 调用示例 (data-to-json '((7 "vince" "vince1@test.com" "space" "no value" 1) (8 "vince" "vince2@test.com" "place" "no value" 1) (9 "Smith" "Smith@gmail.com" "now" "no value" 1)))
要是姓名或邮箱里有双引号这类特殊字符,得加个转义处理,不然JSON会报错:
(defun escape-string (s) (substitute-if #\\ (lambda (c) (char= c #\")) s)) ;; 升级后的转换函数 (defun data-to-json (data) (let ((entries (mapcar (lambda (item) (format nil "{\"name\": \"~a\", \"email\": \"~a\"}" (escape-string (second item)) (escape-string (third item)))) data))) (format nil "[~{~a~^, ~}]" entries)))
方法二:正确用cl-json库
要是还是想用cl-json,别逐个编码,先把所有数据转成Lisp的嵌套列表,再一次性编码:
(defun get-name-emails (item) (list (cons :name (second item)) (cons :email (third item)))) (defun data-to-json-with-cljson (data) (cl-json:encode-json-to-string (mapcar #'get-name-emails data))) ;; 调用示例 (data-to-json-with-cljson (return-data-tree))
这样mapcar会生成一个包含所有键值对列表的大列表,再用encode-json-to-string一次性编码,就能得到单个完整的JSON数组了。
内容的提问来源于stack exchange,提问作者Vinn
相关产品推荐
相关产品推荐

