解码 json 中的事物或事物列表
Decoding a thing or a list of things in json
我正在尝试解析 JSON-LD,其中一种可能的结构是
"John" : {
"type": "person",
"friend": [ "Bob", "Jane" ],
}
我想解码成
类型的记录
type alias Triple =
{ subject: String, predicate: String, object: String }
所以上面的例子变成了:
Triple "John" "type" "person"
Triple "John" "friend" "Bob"
Triple "John" "friend" "Jane"
但是 JSON 对象中的 "friend" 也可以只是一个字符串:
"friend": "Mary"
在这种情况下对应的三元组是
Triple "John" "friend" "Mary"
有什么想法吗?
首先,您需要一种方法来列出 JSON 对象中的所有 key/value 对。 Elm 为此提供了 Json.Decode.keyValuePairs
函数。它为您提供了将用于 predicate
字段的键名称列表,但您还必须描述一个解码器以供其用于值。
由于您的值是字符串或字符串列表,因此您可以使用 Json.Decode.oneOf
来提供帮助。在这个例子中,我们只是将一个字符串转换为一个单例列表(例如 "foo"
变成 ["foo"]
),只是因为这样以后映射起来更容易。
stringListOrSingletonDecoder : Decoder (List String)
stringListOrSingletonDecoder =
JD.oneOf
[ JD.string |> JD.map (\s -> [ s ])
, JD.list JD.string
]
由于 keyValuePairs
的输出将是 (String, List String)
值的列表,我们需要一种方法将这些值扁平化为 List (String, String)
值。我们可以这样定义该函数:
flattenSnd : ( a, List b ) -> List ( a, b )
flattenSnd ( key, vals ) =
List.map (\val -> ( key, val )) vals
现在您可以使用这两个函数将一个对象拆分为一个三元组。这接受一个字符串参数,它是在调用函数中查找的键(例如,我们需要查找包装 "John"
键)。
itemDecoder : String -> Decoder (List Triple)
itemDecoder key =
JD.field key (JD.keyValuePairs stringListOrSingletonDecoder)
|> JD.map
(List.map flattenSnd
>> List.concat
>> List.map (\( a, b ) -> Triple key a b)
)
See a working example here on Ellie.
请注意,键的顺序可能与您在输入 JSON 中列出的顺序不匹配,但这正是 JSON 的工作方式。这是查找 table,不是有序列表
我正在尝试解析 JSON-LD,其中一种可能的结构是
"John" : {
"type": "person",
"friend": [ "Bob", "Jane" ],
}
我想解码成
类型的记录type alias Triple =
{ subject: String, predicate: String, object: String }
所以上面的例子变成了:
Triple "John" "type" "person"
Triple "John" "friend" "Bob"
Triple "John" "friend" "Jane"
但是 JSON 对象中的 "friend" 也可以只是一个字符串:
"friend": "Mary"
在这种情况下对应的三元组是
Triple "John" "friend" "Mary"
有什么想法吗?
首先,您需要一种方法来列出 JSON 对象中的所有 key/value 对。 Elm 为此提供了 Json.Decode.keyValuePairs
函数。它为您提供了将用于 predicate
字段的键名称列表,但您还必须描述一个解码器以供其用于值。
由于您的值是字符串或字符串列表,因此您可以使用 Json.Decode.oneOf
来提供帮助。在这个例子中,我们只是将一个字符串转换为一个单例列表(例如 "foo"
变成 ["foo"]
),只是因为这样以后映射起来更容易。
stringListOrSingletonDecoder : Decoder (List String)
stringListOrSingletonDecoder =
JD.oneOf
[ JD.string |> JD.map (\s -> [ s ])
, JD.list JD.string
]
由于 keyValuePairs
的输出将是 (String, List String)
值的列表,我们需要一种方法将这些值扁平化为 List (String, String)
值。我们可以这样定义该函数:
flattenSnd : ( a, List b ) -> List ( a, b )
flattenSnd ( key, vals ) =
List.map (\val -> ( key, val )) vals
现在您可以使用这两个函数将一个对象拆分为一个三元组。这接受一个字符串参数,它是在调用函数中查找的键(例如,我们需要查找包装 "John"
键)。
itemDecoder : String -> Decoder (List Triple)
itemDecoder key =
JD.field key (JD.keyValuePairs stringListOrSingletonDecoder)
|> JD.map
(List.map flattenSnd
>> List.concat
>> List.map (\( a, b ) -> Triple key a b)
)
See a working example here on Ellie.
请注意,键的顺序可能与您在输入 JSON 中列出的顺序不匹配,但这正是 JSON 的工作方式。这是查找 table,不是有序列表