使用 hl_yaml 反序列化和后处理 YAML 数据
任务
数据格式 / YAML / 反序列化和后处理 YAML 数据
反序列化一个结构没有直接映射到 OCaml 类型 的 YAML 文件。
使用的 Opam 包
- hl_yaml 测试版本: 1.0.0 — 使用库: hl_yaml
- ppx_deriving_yojson 测试版本: 3.7.0 — 使用库: ppx_deriving_yojson
代码
此 YAML 字符串包含一个配料列表,其中配料以 YAML 对象形式表示,键表示名称,值表示数量。
let yaml = {|
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_yojson]
属性使 ppx_deriving_yojson
库生成函数 ingredient_of_yojson : Yojson.Safe.t -> (ingredient, string) result
。
type ingredient = {
name: string;
weight: int;
} [@@deriving of_yojson]
[@@deriving of_yojson]
属性使 ppx_deriving_yojson
库生成函数 recipe_of_yojson : Yojson.Safe.t -> (ingredient, string) result
。
type recipe = {
name: string; [@key "french name"]
ingredients: ingredient list;
steps: string list;
} [@@deriving of_yojson]
由于 YAML 文件的结构与 recipe
类型不完全匹配,我们 (1) 将 YAML 文件解析为 Yojson.Safe.t
表示形式,然后 (2) 修改 Yojson.Safe.t
值以更改结构以匹配 recipe
类型,这样我们就可以使用 recipe_of_yojson
函数。
函数 add_keys
和 at_ingredients
执行此后处理。
let add_keys = function
| `Assoc [(name, `Int weight)] ->
`Assoc [
("name", `String name);
("weight", `Int weight);
]
| v -> v
let at_ingredients f = function
| `Assoc [
("french name", `String name);
("ingredients", `List ingredients);
("steps", `List steps)
] -> `Assoc [
("french name", `String name);
("ingredients",
Yojson.Safe.Util.map f (`List ingredients));
("steps", `List steps);
]
| v -> v
解析、后处理并将 YAML 字符串转换为 recipe
类型的 OCaml 值。
let pate_sucree =
let of_yojson json =
json
|> at_ingredients add_keys
|> recipe_of_yojson in
yaml
|> Hl_yaml.Unix.parse ~of_yojson