alwaysday1
alwaysday1

Reputation: 1783

How to update JSON object using Yojson?

After reading some examples, it's easy to construct a JSON object by Yojson.Basic.from_string or from_channel.

On the other side, we could also easily to convert a JSON object to string by pretty_to_string.

However, update an JSON object is tricky, for example the input parameter is as follows:

{
    "content": "test content",
    "base" : {
        "version": 1,
        "id" : "a001"
    }
}

I want to update the "id" in it and return a new JSON object:

{
    "content": "test content",
    "base" : {
        "version": 1,
        "id" : "a002"
    }
}

I tried to write a function to update a JSON object:

let update_json (js: json) (key: string) (new_value: string) : json =
  let rec aux (json_ele:json):json = 
    match json_ele with
    | `Bool b -> `Bool b
    | `Float f -> `Float f
    | `Int i -> `Int i
    | `List jl -> `List (List.map jl ~f:aux)
    | `Null -> `Null
    | `String st -> `String st
    | `Assoc kvlist -> 
        `Assoc (
        List.map
          kvlist
          ~f:(fun (okey, ovalue) -> 
              match ovalue with
              | `String v when okey = key -> (okey, `String new_value)
              | _ -> (okey, aux ovalue)))
  in
  aux js

I was wondering if writing a function as above is the best way to update a JSON object in Yojson?

Upvotes: 2

Views: 760

Answers (1)

antron
antron

Reputation: 3847

I'm not clear on what you mean by "bugs", but `Assoc doesn't take a string * json, it takes a (string * json) list. This means that in your `Assoc cases, you should do a List.map:

| `Assoc pairs ->
  List.map pairs ~f:(fun (okey, ovalue) ->
    if okey = key then
      key, new_value
    else
      okey, aux ovalue)

You may want to factor this function out and give it a name.

Upvotes: 1

Related Questions