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

Clojure读取大型嵌套JSON时如何保留键的原始顺序?

如何在Clojure中读取JSON时保留键的原始顺序?

用户的依赖配置 (deps.edn)

{
 :deps
 {
  org.clojure/data.json   {:mvn/version "2.4.0"}
  org.clojure/data.csv    {:mvn/version "1.1.0"}
  org.flatland/ordered        {:mvn/version "1.4.0"}
  metosin/jsonista {:mvn/version "0.3.8"}
  com.cognitect/transit-clj {:mvn/version "1.0.333"}
  }}

用户的代码

(ns ordering-json
  (:require
   [clojure.data.csv :as csv]
   [clojure.data.json :as json]
   [jsonista.core :as json2]
   [clojure.java.io :as io]
   [clojure.string :as string]
   [clojure.test :as t]
   [flatland.ordered.map :refer [ordered-map]]
   ))

(defn save-as-json [of data]
  (with-open [writer (io/writer of)]
    (json/write data writer)))

(defn read-f [f out]
  (let [data (json/read-str (slurp  f)
                            :key-fn (fn [k] (if (empty? k) "" k))
                            :map-fn ordered-map
                            )]
    (prn data)
    (save-as-json out data)))

(read-f "./data/standards.json" "./data/modified.json")

问题描述

使用多个JSON反序列化工具读取JSON时,小型文件能保留键顺序,但处理大型嵌套JSON文件时,键的原始顺序会被打乱,希望找到读取时保留键顺序的方法。


解决方案

1. 修复clojure.data.json的嵌套对象解析问题

你当前的代码仅给顶层JSON对象指定了:map-fn ordered-map,但嵌套的JSON对象仍会使用默认的无序map。需要通过:value-fn递归处理所有嵌套对象:

(defn read-f [f out]
  (let [parse-nested (fn [key value]
                       (if (map? value)
                         (into (ordered-map) value)
                         value))
        data (json/read-str (slurp f)
                            :key-fn (fn [k] (if (empty? k) "" k))
                            :map-fn ordered-map
                            :value-fn parse-nested)]
    (prn data)
    (save-as-json out data)))

parse-nested函数会检查每个解析值,若为map类型(即嵌套JSON对象),就转换为ordered-map,确保所有层级的键顺序都被保留。

2. 使用jsonista实现更简洁的嵌套有序解析

jsonista支持直接配置object-mapper,让所有JSON对象(包括嵌套的)都使用ordered-map:

(defn read-f-jsonista [f out]
  (let [mapper (json2/object-mapper
                {:decode-key-fn (fn [k] (if (empty? k) "" k))
                 :decode-object-fn (fn [m] (into (ordered-map) m))})
        data (json2/read-value (slurp f) mapper)]
    (prn data)
    (json2/write-value out data)))

:decode-object-fn会作用于所有解析出的JSON对象,无需额外递归处理,就能实现全层级的键顺序保留。

验证注意事项

  • 写入JSON时,clojure.data.json和jsonista都会按ordered-map的顺序输出键,无需额外配置。
  • 处理超大型JSON文件时,建议使用流式解析(如jsonista的流式API),避免一次性加载整个文件到内存,同时流式解析也能通过配置保留键顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:07:38