Reputation: 179
The only examples I can see so far about processing json objects involve knowing the key beforehand, but how would I be able to go through the keys/members and process their values individually?
Upvotes: 1
Views: 1040
Reputation: 4939
Yojson was designed to serve as the runtime for atdgen. Atdgen saves users a lot of time by translating JSON data into data of your OCaml types and vice-versa.
The solution for JSON objects representing association lists is the following (sample source file assoc.atd
):
type t = (string * foo) list <json repr="object"> type foo = { x: int; y: int; }
Sample data of type t
in JSON format:
{ "p1": { "x": 1, "y": 2 }, "p2": { "x": 14, "y": 0 }, "q": { "x": 9, "y": -1 } }
The generated interface for this example is:
(* 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}. *)
Upvotes: 2
Reputation: 20014
Assuming you've created a json
instance, perhaps by reading from a file using Yojson.Basic.from_channel (open_in filename)
or from a string using Yojson.Basic.from_string string
, you could then convert it to an association list using Yojson.Basic.Util.to_assoc
and recursively iterate over it like this:
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)
This iter
function first converts its js
argument to an association list and then iterates over it using function f
. The f
function takes a tuple argument of a string and a json
type. For the sake of this example it prints the string, then matches the json
type and acts on it accordingly. Note how f
handles the values for the `Assoc
and `List
variants recursively.
Upvotes: 2