You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Clojure新手技术求助:从JSON文件数组提取嵌套数据与键列表

Clojure新手JSON处理指南:提取键列表与嵌套数据

嘿,作为Clojure新手,这两个JSON处理任务其实是日常开发里的高频操作,我来一步步给你拆解清楚~

首先明确前提:你已经把目录里的JSON文件通过slurp读成了字符串数组,接下来需要先把这些字符串解析成Clojure的原生数据结构(比如map、vector),我们会用到clojure.data.json库来做解析。

第一步:准备工作(依赖与数据加载)

首先确保你的项目里引入了JSON解析依赖,如果是Leiningen的project.clj,加上这一行:

[org.clojure/data.json "2.4.0"]

然后加载目录下的所有JSON文件并解析:

(require '[clojure.data.json :as json])
(require '[clojure.java.io :as io])

;; 读取指定目录下的所有JSON文件,解析为Clojure数据结构
(def invoice-files
  (->> (io/file "./your-invoice-directory")  ;; 替换成你的JSON文件目录
       file-seq
       (filter #(.isFile %))
       (map slurp)
       (map json/read-string)))

任务1:提取JSON的键列表

从你的示例结构看,单个JSON文件解析后是一个vector,里面包含一个发票map。我们需要先取到这个map,再提取它的顶层键。

单个发票的键列表

如果只处理单个文件的数据:

;; 假设single-file-data是单个解析后的JSON数据
(def single-file-data (first invoice-files))
(def top-level-keys (keys (first single-file-data)))
;; 输出会是(:id :lines :date :total :invoice-ad...)

批量处理所有文件的键列表

如果要处理所有文件的发票键列表,用map遍历即可,同时用some->避免空数组的情况(防止报错):

(def all-invoice-keys
  (map #(some-> % first keys) invoice-files))

解释:some->会依次执行每个步骤,如果中间某一步返回nil(比如某个文件是空数组),就直接返回nil,不会抛出NullPointerException


任务2:提取嵌套数据

嵌套数据的核心是通过关键字(keyword)逐层访问map,结合map、mapcat等函数批量处理。以下是几个常见场景的示例:

场景1:提取每个发票的ID、日期和总金额

(def invoice-summary
  (map (fn [file-data]
         (let [invoice (first file-data)]  ;; 取文件中的发票对象
           {:id (:id invoice)
            :date (:date (:date invoice))  ;; 嵌套访问date里的date字段
            :total-GBP (:GBP (:total invoice))}))  ;; 取total里的GBP金额
       invoice-files))

场景2:提取所有商品行的描述与价格

如果要把所有文件里的商品行(lines)都提取出来合并成一个列表,用mapcat(相当于先map再concat):

(def all-line-items
  (mapcat (fn [file-data]
            (let [invoice (first file-data)]
              (map (fn [line]
                     {:description (:description line)
                      :price-GBP (:GBP (:price line))})
                   (:lines invoice))))  ;; 遍历当前发票的所有lines
          invoice-files))

场景3:提取特定条件的嵌套数据

比如只想提取总金额大于20的发票信息:

(def high-value-invoices
  (filter (fn [file-data]
            (let [invoice (first file-data)
                  total (:GBP (:total invoice))]
              (> total 20)))
          invoice-files))

小技巧提醒

  • 如果你不确定某个嵌套路径是否存在,可以用get-in函数,它支持默认值:
    ;; 如果:total里没有:GBP,返回0而不是nil
    (get-in invoice [:total :GBP] 0)
    
  • 对于复杂的JSON结构,推荐用clojure.walk里的函数来递归处理,比如walk、postwalk。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:29:44