如何在Elm中操作Json.Encode.Value?

3
我正在编写一些代码,用于自动生成Elm数据结构的JSON编解码器。在我的代码中,有一个“子结构/子类型”,已经被编码成了Json.Encode.Value,我需要向其添加另一个键值对。在Elm中是否有任何方法可以“解构”Json.Encode.Value?或者将两个类型为Json.Encode.Value的值合并?
以下是一些示例代码:
type alias Entity record =
   { entityKey: (Key record)
   , entityVal: record
   }

jsonEncEntity : (record -> Value) -> Entity record -> Value
jsonEncEntity localEncoder_record val =
  let 
      encodedRecord = localEncoder_record val.entityVal
  in
      -- NOTE: the following line won't compile, but this is essentially
      -- what I'm looking for
      Json.combine encodedRecord (Json.Encode.object [ ( "id", jsonEncKey val.entityKey ) ] )

1
你最好延迟编码,直到最后一刻才对子结构/子类型进行编码;也就是在不再需要原始结构之后的那一刻。Json.Encode.Value 是一个不透明/黑盒(https://en.wikipedia.org/wiki/Opaque_data_type)数据类型。因此,它不适合被解构。通过重新设计你的应用程序来避免这个需求,可以省去很多麻烦。 - undefined
2个回答

3
您可以使用D.keyValuePairs D.value将值解码为键值对列表,然后添加新字段。以下是如何执行此操作的示例:
module Main exposing (..)

import Json.Decode as D
import Json.Encode as E exposing (Value)


addKeyValue : String -> Value -> Value -> Value
addKeyValue key value input =
    case D.decodeValue (D.keyValuePairs D.value) input of
        Ok ok ->
            E.object <| ( key, value ) :: ok

        Err _ ->
            input

> import Main
> import Json.Encode as E
> value = E.object [("a", E.int 1)]
{ a = 1 } : Json.Encode.Value
> value2 = Main.addKeyValue "b" E.null value
{ b = null, a = 1 } : Json.Encode.Value

如果输入不是对象,它将返回未改变的输入。
> Main.addKeyValue "b" E.null (E.int 1)
1 : Json.Encode.Value

我试图避免使用decode*系列的方法。先编码,然后立即解码,再次编码,这似乎非常违反直觉。你知道这种解码的效率如何吗?我尝试查看Native.Json模块,但无法理解其中的操作。 - undefined
解码为键值对只需要遍历JS对象的键一次,并创建一个包含键和值的2元组链表。编码则相反,将一个元组列表转换为对象。如果您连续进行编码/解码操作,值将不会被修改。这个过程应该非常快速,至少比人们预期的JSON.stringify/JSON.parse要快得多。 - undefined
你可能想通过一些基准测试来确认我上面所说的。这是我从https://github.com/elm/json的当前主分支中所理解的内容。 - undefined

1
如果您想要这样做,您需要使用解码器将值解包一级到Dict String Value中,然后组合字典,最后重新编码为JSON值。您可以像这样解包:
unwrapObject : Value -> Result String (Dict String Value)
unwrapObject value =
    Json.Decode.decodeValue (Json.Decode.dict Json.Decode.value) value

注意,从现在开始你必须使用 Result,因为在 Elm 中存在这样的可能性,即你的 JSON 值实际上不是一个对象(例如它可能是一个数字或字符串),你必须处理这种情况。因此,最好不要直接对 JSON Value 进行操作;如果可以的话,保持其为 Dict 或其他更具信息量的类型,直到处理完成,然后将整个结果转换为 Value 作为最后一步。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接