Clojure Spec验证失败:JSON解析数据不符合规格定义
解决Clojure Spec验证JSON数据失败的两个问题
针对你遇到的两个验证失败问题,直接给你可行的解决办法:
问题1:解析后的数据外层带:invoice键,与Spec期望的内部结构不匹配
你有两种选择来修复:
选项1:调整Spec结构,适配外层的:invoice键
新增一个顶层Spec来匹配整个JSON的外层结构,内部复用你已定义的::invoice/invoice:
(require '[clojure.spec.alpha :as s]) ;; 新增顶层wrapper Spec (s/def ::invoice-wrapper (s/keys :req-un [::invoice/invoice])) ;; 验证时使用这个新Spec (s/valid? ::invoice-wrapper (invoice "invoice.json"))
选项2:验证前提取:invoice对应的内部数据
直接从解析后的map中取出:invoice的值再验证,不用改原Spec:
(s/valid? ::invoice/invoice (:invoice (invoice "invoice.json")))
问题2:JSON中retentions的tax_rate是double类型,与Spec的int?定义不匹配
根据业务需求选下面的方案:
方案1:放宽Spec的类型限制(允许整数和浮点数)
如果业务上tax_rate可以是数字类型(不管整数还是小数),把Spec里的int?改成number?:
(s/def ::tax_rate number?)
方案2:解析JSON时将double转成整数(如果业务要求必须是整数)
如果tax_rate必须是整数,在解析JSON时把符合整数条件的double转成int。假设你用cheshire解析JSON,可以加自定义解码逻辑:
(require '[cheshire.core :as json]) (defn parse-invoice [path] (json/parse-string (slurp path) true {:key-fn keyword ;; 把整数型的double转成int,非整数的保持原样(可选调整) :decode-double (fn [d] (if (zero? (rem d 1)) (int d) d))})) ;; 验证时用解析后的结果 (s/valid? ::invoice/invoice (:invoice (parse-invoice "invoice.json")))
如果已经有解析函数,也可以手动遍历数据转换tax_rate:
(defn fix-tax-rates [invoice-data] (update invoice-data :retentions (fn [retentions] (mapv #(update % :tax_rate int) retentions)))) ;; 先提取内部数据,再修复类型,最后验证 (s/valid? ::invoice/invoice (-> (invoice "invoice.json") :invoice fix-tax-rates))
内容的提问来源于stack exchange,提问作者vcFull
相关产品推荐
相关产品推荐

