🐻

RustでJSONを扱う(serde_json) JSONの編集

2023/08/13に公開

サンプル

serde_json::Value を編集する

これまでの記事では serde_json を使ったJSONの読み込みについて述べてきたが、JSONを編集したくなっても来るだろう。
serde_json::Value でパースされたJSONを編集していく。

下記のようにJSONを読み込んでおく。

let json = from_reader::<BufReader<File>, Value>(reader);
let mut json: Value = match json {
    Ok(o) => o,
    Err(e) => {
        println!("Failed to parse json.");
        return Err(Box::new(e));
    }
};
// 変数 "json" に読み込まれたJSON
//{
//  "live_music_club": "STARRY",
//  "o-ne-chan": {
//    "name": "Seika",
//    "age": 29
//  },
//  "band": [
//    {
//      "band_name": "Kessoku Band",
//      "member": [
//        {
//          "name": "Nijika",
//          "age": 17
//        },
//        {
//          "name": "Ryo",
//          "age": 16
//        },
//        {
//          "name": "Goto",
//          "age": 15
//        },
//        {
//          "name": "Ikuyo",
//          "age": 16
//        }
//      ]
//    }
//  ]
//}

get_mut() で書き換える

mutableな参照を取得

let target_member: &Value = &json["band"][0]["member"][3];
if target_member.is_null() {
    return Err("Failed to get member".into());
}

let target_name: Option<&mut Value> = json["band"][0]["member"][3].get_mut("name");
let target_name: &mut Value = match target_name {
    Some(s) => s,
    None => {
        return Err("Failed to get name".into());
    }
};

ここで "json["band"][0]["member"]" は "{"name": "Ikuyo", "age": 16 }" のことであるが、もし存在しない場合 serde_json::Value::Nullget_mut() しようとしてpanicを起こす。
そのためあらかじめ is_null() な場合を弾いた。

代入

上で取得した "json["band"][0]["member"][3]["name"]" にderefし、serde_json::Value を代入する。

let new_name: String = String::from("Kita");
println!("\"Kita-ikuyo-tte-ahoka-i\"");
println!("Fix : {} -> {}", target_name, new_name);

*target_name = Value::String(new_name);

出力結果

サンプルを実行すると下記のようになる。

{"band":[{"band_name":"Kessoku Band","member":[{"age":17,"name":"Nijika"},{"age":16,"name":"Ryo"},{"age":15,"name":"Goto"},{"age":16,"name":"Ikuyo"}]}],"live_music_club":"STARRY","o-ne-chan":{"age":29,"name":"Seika"}}

"Kita-ikuyo-tte-ahoka-i"
Fix : "Ikuyo" -> Kita
{"band":[{"band_name":"Kessoku Band","member":[{"age":17,"name":"Nijika"},{"age":16,"name":"Ryo"},{"age":15,"name":"Goto"},{"age":16,"name":"Kita"}]}],"live_music_club":"STARRY","o-ne-chan":{"age":29,"name":"Seika"}}

バンドメンバーの4人目の名前が "Ikuyo" から "Kita" に変更されているはずである。

[] (square brackets) で書き換える

こちらのほうが直感的でわかりやすいかもしれない。

let new_name_2: String = String::from("Hitori");
println!("\"Goto sa...\"");
println!("Fix : {} -> {}", json["band"][0]["member"][2]["name"], new_name_2);

json["band"][0]["member"][2]["name"] = Value::String(new_name_2);

しかし存在しないキーならば単純に追記されるが、"json["band"][0]["member"][100]" などに追記しようとするとpanicを起こすため、 get_mut() のほうが安全に扱えるだろう。

新しい値を挿入する

バンドメンバーの楽器を追記したい。

let instrument = "Guiter".to_string();

json["band"][0]["member"][2]["instrument"] = Value::String(instrument.clone());

let target_member: Option<&mut serde_json::Map<String, Value>> = json["band"][0]["member"][3].as_object_mut();
if let Some(s) = target_member {
    s.insert(String::from("instrument"), instrument.clone().into());
}

1つ目は前述の存在しない場合のキーは新規で作られるので直接代入してしまうことができる。

2つ目は代入するためのmutableなobjectを as_object_mut() で取得してそこに insert() で挿入している。

Reference

Discussion