使用 yaml 反序列化和後處理 YAML 資料

任務

資料格式 / YAML / 反序列化和後處理 YAML 資料

反序列化一個 YAML 檔案,其結構並未直接對應到某些 OCaml 類型。

使用的 Opam 套件

  • yaml 測試版本:3.2.0 — 使用的函式庫:yaml
  • ppx_deriving_yaml 測試版本:0.2.2 — 使用的函式庫:ppx_deriving_yaml

程式碼

這個 YAML 字串包含一個食材列表,其中食材以 YAML 物件表示,鍵表示名稱,值表示數量。

let yaml_string = {|
french name: pâte sucrée
ingredients:
- flour: 250
- butter: 100
- sugar: 100
- egg: 50
- salt: 5
steps:
- soften butter
- add sugar
- add egg and salt
- add flour
|}

[@@deriving of_yaml] 屬性使 ppx_deriving_yaml 函式庫產生函式 ingredient_of_yaml : Yaml.value -> (ingredient, [> `Msg of string]) result

type ingredient = {
  name: string;
  weight: int;
} [@@deriving of_yaml]

[@@deriving of_yaml] 屬性使 ppx_deriving_yaml 函式庫產生函式 recipe_of_yaml : Yaml.value -> (ingredient, [> `Msg of string]) result

type recipe = {
  name: string; [@key "french name"]
  ingredients: ingredient list;
  steps: string list;
} [@@deriving of_yaml]

由於 YAML 檔案的結構與 recipe 類型不完全匹配,我們 (1) 將 YAML 檔案解析為 yaml 套件的內部表示法 Yaml.value,然後 (2) 更改結構以符合 recipe 類型,以便可以使用 recipe_of_yaml 函式。

函式 add_keysat_ingredients 執行此後處理。

let add_keys = function
  | `O [(name, `Float weight)] ->
      `O [
        ("name", `String name);
        ("weight", `Float weight);
      ]
  | v -> v

let at_ingredients f = function
  | `O [
      ("french name", `String name);
      ("ingredients", `A ingredients);
      ("steps", `A steps)
    ] -> `O [
      ("french name", `String name);
      ("ingredients",
        Yaml.Util.map_exn f (`A ingredients));
      ("steps", `A steps);
    ]
  | v -> v

解析、後處理,並將 YAML 字串轉換為 recipe 類型的 OCaml 值。

let pate_sucree =
  yaml_string
  |> Yaml.of_string
  |> Result.map (at_ingredients add_keys)
  |> fun yaml -> Result.bind yaml recipe_of_yaml

食譜無法運作?註解不清楚或過時?

開啟一個 issue貢獻此食譜

此任務的其他食譜