使用 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_keys
和 at_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