如何使用argonaut镜头修改JSON中的值和类型?

如何使用argonaut镜头修改JSON中的值和类型?,json,scala,scalaz,lenses,argonaut,Json,Scala,Scalaz,Lenses,Argonaut,假设以下是简单的JSON文档: { "key" : "val1" } 我想更新key的值,但同时也要更改其类型,因此从string将其更改为int。现在,使用下面类似的HCursor可以直接执行此操作: val cursor = js.hcursor val position = (cursor --\ "key") >-> (_ => jNumber(1)) 通过撤销上面的位置,我得到了一个新的json,其中key有一个数

假设以下是简单的JSON文档:

       {
         "key" : "val1"
       }
我想更新key的值,但同时也要更改其类型,因此从string将其更改为int。现在,使用下面类似的HCursor可以直接执行此操作:

 val cursor = js.hcursor
 val position = (cursor --\ "key") >-> (_ => jNumber(1))
通过撤销上面的位置,我得到了一个新的json,其中key有一个数值而不是字符串,这是完美的

用镜头也能做到这一点吗?我试着做到以下几点:

val lense = jObjectPL >=>
          jsonObjectPL("key") >=>
          jNumberPL
lense.mod(_ => JsonBigDecimal(1), js)

但是,虽然我没有收到错误,但它也不起作用,最后我得到了未修改的原始json文档。但是,如果我尊重数据类型,那么事情就应该正常工作。是否有理由认为透镜只能用于修改相同的数据类型?或者我只是做错了什么:

不,没什么大不了的,你就快到了。问题在于,这条路径:

jObjectPL >=> jsonObjectPL("key") >=> jNumberPL
导航到键处的JSON编号。你的js键上没有JSON数字,所以镜头不会指向任何东西,修改也不会影响任何东西

您只需删除镜头的最后一步即可解决此问题:

val lens = jObjectPL >=> jsonObjectPL("key")
这只是导航到键字段,但不限制它是什么类型的JSON值。然后,您可以将其更改为您想要的任何内容:

scala> val lens = jObjectPL >=> jsonObjectPL("key")
lens: scalaz.PLensFamily[...

scala> lens.mod(_ => jNumber(JsonBigDecimal(1)), js)
res0: argonaut.Json = {"key":1}

请注意,由于镜头指向的是Json值,而不是JsonNumber,因此您必须将JsonBigDecimal封装在jNumber中,以使类型对齐。

感谢@Travis提供的快速答案!非常感谢。在阅读lents&Argonaut的文档时,我的印象是,您应该始终定义所期望的JSON数据类型。但我想,有时把事情复杂化是人类本性的一部分:@cpard-Yep:。在这种情况下,您希望在该位置有一个JSON字符串,但是如果将jStringPL添加到镜头中,您将无法更改该类型。