如何使用 Yojson 遍历 JSON 对象中的 keys/members?

How do you iterate through the keys/members in a JSON object using Yojson?

到目前为止,我能看到的关于处理 json 对象的唯一示例涉及事先知道密钥,但我如何才能通过 keys/members 并单独处理它们的值?

假设您已经创建了一个 json 实例,也许通过使用 Yojson.Basic.from_channel (open_in filename) 从文件中读取或使用 Yojson.Basic.from_string string 从字符串中读取,然后您可以将其转换为关联列表使用 Yojson.Basic.Util.to_assoc 并像这样递归迭代它:

open Yojson.Basic

let iter js =
  let rec f (nm,j) =
    Printf.printf "\"%s\": " nm;
    match j with
    | `Assoc a ->
       Printf.printf "assoc\n";
       List.iter f a
    | `Bool b ->
       Printf.printf "bool: %b\n" b
    | `Float f ->
       Printf.printf "float: %f\n" f
    | `Int i ->
       Printf.printf "int: %d\n" i
    | `List jl ->
       Printf.printf "list: [";
       List.iter (List.iter f) (List.map Util.to_assoc jl);
       Printf.printf "]\n"
    | `Null ->
       Printf.printf "null\n"
    | `String s ->
       Printf.printf "string: \"%s\"\n" s in
  List.iter f (Util.to_assoc js)

iter 函数首先将其 js 参数转换为关联列表,然后使用函数 f 对其进行迭代。 f 函数接受字符串和 json 类型的元组参数。为了这个例子,它打印字符串,然后匹配 json 类型并相应地对其进行操作。请注意 f 如何递归地处理 `Assoc`List 变体的值。

Yojson 旨在用作 atdgen 的运行时。 Atdgen 通过将 JSON 数据转换为您的 OCaml 类型的数据,反之亦然,为用户节省了大量时间。

solution for JSON objects representing association lists 如下(示例源文件 assoc.atd):

type t = (string * foo) list <json repr="object">

type foo = {
  x: int;
  y: int;
}

t 类型的样本数据 JSON 格式:

{
  "p1": { "x": 1, "y": 2 },
  "p2": { "x": 14, "y": 0 },
  "q": { "x": 9, "y": -1 }
}

本例生成的界面为:

(* This is file assoc_j.mli derived from assoc.atd.
   It provides the serializers and deserializers for JSON.
   Other files are generated for other purposes,
   including assoc_t.mli which contains only the OCaml
   type definitions.
 *)

type foo = Assoc_t.foo = { x: int; y: int }

type t = Assoc_t.t

val write_foo :
  Bi_outbuf.t -> foo -> unit
  (** Output a JSON value of type {!foo}. *)

val string_of_foo :
  ?len:int -> foo -> string
  (** Serialize a value of type {!foo}
      into a JSON string.
      @param len specifies the initial length
                 of the buffer used internally.
                 Default: 1024. *)

val read_foo :
  Yojson.Safe.lexer_state -> Lexing.lexbuf -> foo
  (** Input JSON data of type {!foo}. *)

val foo_of_string :
  string -> foo
  (** Deserialize JSON data of type {!foo}. *)

val write_t :
  Bi_outbuf.t -> t -> unit
  (** Output a JSON value of type {!t}. *)

val string_of_t :
  ?len:int -> t -> string
  (** Serialize a value of type {!t}
      into a JSON string.
      @param len specifies the initial length
                 of the buffer used internally.
                 Default: 1024. *)

val read_t :
  Yojson.Safe.lexer_state -> Lexing.lexbuf -> t
  (** Input JSON data of type {!t}. *)

val t_of_string :
  string -> t
  (** Deserialize JSON data of type {!t}. *)