在json中解码事物或事物列表

Unl*_*din 3 json elm

我正在尝试解析JSON-LD,其中一个可能的构造是

"John" : { 
  "type": "person",
  "friend": [ "Bob", "Jane" ],
}
Run Code Online (Sandbox Code Playgroud)

我想解码成类型的记录

type alias Triple = 
  { subject: String, predicate: String, object: String }
Run Code Online (Sandbox Code Playgroud)

所以上面的例子变成:

Triple "John" "type" "person"
Triple "John" "friend" "Bob"
Triple "John" "friend" "Jane"
Run Code Online (Sandbox Code Playgroud)

但是JSON对象中的"friend"也可能只是一个字符串:

"friend": "Mary"
Run Code Online (Sandbox Code Playgroud)

在这种情况下,相应的三元组将是

Triple "John" "friend" "Mary"
Run Code Online (Sandbox Code Playgroud)

任何的想法?

Cha*_*ert 5

首先,您需要一种方法来列出JSON对象中的所有键/值对.榆树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
        ]
Run Code Online (Sandbox Code Playgroud)

由于输出keyValuePairs将是一个(String, List String)值列表,我们需要一种方法将它们展平为一个List (String, String)值.我们可以像这样定义这个函数:

flattenSnd : ( a, List b ) -> List ( a, b )
flattenSnd ( key, vals ) =
    List.map (\val -> ( key, val )) vals
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用这两个函数将对象拆分为三元组.这接受一个字符串参数,这是查询调用函数的关键(例如,我们需要查找包装"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)
            )
Run Code Online (Sandbox Code Playgroud)

在Ellie上看到一个工作示例.

请注意,键的顺序可能与您在输入JSON中列出它们的方式不匹配,但这就是JSON的工作原理.它是一个查找表,而不是一个有序列表