在Scala中解析和操作Json

6
我从使用的REST服务中获得了这个JSON。
{
    "id": "6804",
    "signatories": [
        {
            "id": "12125",
            "fields": [
                {
                    "type": "standard",
                    "name": "fstname",
                    "value": "John"
                },
                {
                    "type": "standard",
                    "name": "sndname",
                    "value": "Doe"
                },
                {
                    "type": "standard",
                    "name": "email",
                    "value": "john.doe@somwhere.com"
                },
                {
                    "type": "standard",
                    "name": "sigco",
                    "value": "Company"
                }
            ]
        }
    ]
}

我正在寻找一种使用json4s解析此内容的方法,遍历“fields”数组,以便能够更改其中不同对象的属性“value”。到目前为止,我已经尝试了几个json库,并最终选择了json4s

Json4s允许我将json解析为JObject,我可以尝试从中提取“fields”数组。

    import org.json4s._
    import org.json4s.native.JsonMethods._

    // parse to JObject
    val data = parse(json)

    // extract the fields into a map
    val fields = data \ "signatories" \ "fields"

    // parse back to JSON
    println(compact(render(fields)))

我已经提取了一个类似这样的地图,并将其呈现为JSON。但我无法弄清楚如何遍历这些字段并更改它们中的属性“value”。我已经阅读了json4s文档,但我对Scala和它的语法都很陌生,所以我很难理解。问题是,如何迭代已解析的JSON结果以更改属性“value”?以下是我想要实现的流程:
1. 将JSON解析为可迭代对象 2. 循环查找特定的“名称”并更改其值,例如将fstname从John更改为其他名称。 3. 将其重新解析为JSON,以便可以发送带有更新值的新JSON。
我不知道这是否是完成此操作的最佳方法,我真的很感激您的意见,也许有一种更简单的方法来完成这个任务。谢谢您的帮助!
最好的问候, Stefan Konno

什么问题? - Theolodis
如何循环遍历这些字段并更改它们的“值”属性? - Stefan Konno
您可以始终使用 \ 运算符而无需反序列化对象。 - bkowalikpl
1个回答

6
您可以将json转换为case class数组,这是最简单的方法。例如:您可以为Fields创建case class,如下所示:
case class Field(`type`: String, name: String, value: String)

你可以将json转换为字段数组,例如read[Array[Field]](json),其中json为:

 [
            {
                "type": "standard",
                "name": "fstname",
                "value": "John"
            },
            ...
        ]

这将会给你一个字段的数组。同样地,你可以对整个Json进行建模。

现在你已经有了一个案例类的数组,使用案例类的copy方法迭代对象并更改值相当简单。

之后,为了将对象数组转换成Json,你可以简单地使用write(objects)(Json4s的读写函数可在org.json4s.native.Serialization包中找到)。

Update 

如果不将其转换为case类,您可以使用transformField函数进行操作。

parse(json).transformField{case JField(x, v) if x == "value" && v == JString("Company")=> JField("value1",JString("Company1"))}

是的,这不应该是问题。将您的整个具有50个字段的JSON转换为具有适当字段的案例类(字段可以是简单的,也可以是复杂的,如其他较小案例类的列表)。使用案例类的copy方法随意更改字段。然后将主要案例类的实例转换为JSON。我已经使用json4s对大型JSON进行了处理。看起来非常整洁。每个案例类都有不到5个字段,主类大约有10个字段。 - mohit
不幸的是,对于一个简单的 case class,你会遇到 22 个参数的限制,这使得使用生成的格式化程序有点麻烦。你需要编写自己的 apply/unapply 方法。 - Lionel Port
非常感谢大家的反馈,但我对Scala非常陌生,我只是想使用spray.io编写一个简单的REST接口,以便将来进行评估,但目前我对这个json问题感到非常沮丧。由于json操作非常复杂,我很可能无法完成它。不管怎样,还是感谢大家的反馈,我已经将其标记为答案。 - Stefan Konno
@StefanKonno 没问题。在我看来,拥有50个字段的Json不是一个好的设计。它总是可以被拆分成具有类似属性的嵌套Json,而json4s可以将其转换为带有一行代码的顶级case类。如果这不可能,那么您可以使用transformField方法处理简单情况。否则,scala 2.11.x提供了具有超过22个字段的case类,但我还没有遇到需要超过22个字段的场景。 - mohit
是的,你说得对,我正在使用的服务相当麻烦。因为我需要将整个 JSON 发送回去(只是有几个字段发生了变化)。所以我完全同意你的看法。我会尝试一下 transformField 方法。再次感谢你的时间。 - Stefan Konno
显示剩余3条评论

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