gson 如何修改JsonObject得值

inn6fuwd  于 2022-11-06  发布在  其他
关注(0)|答案(5)|浏览(265)

我想给jsonObject添加一个新字段,这个新字段的名称将基于另一个字段的值。为了清楚起见,这是我想实现的一个示例。

  1. {
  2. "values": [
  3. {
  4. "id": "1",
  5. "properties": [
  6. {
  7. "stat": "memory",
  8. "data": 8
  9. },
  10. {
  11. "stat": "cpu",
  12. "data": 4
  13. }
  14. ]
  15. },
  16. {
  17. "id": "2",
  18. "properties": [
  19. {
  20. "stat": "status",
  21. "data": "OK"
  22. },
  23. {
  24. "stat": "cpu",
  25. "data": 4
  26. }
  27. ]
  28. }
  29. ]
  30. }

我想给每个json对象添加一个新的字段,该字段的值为“stat”作为名称。

  1. {
  2. "values": [
  3. {
  4. "id": "1",
  5. "properties": [
  6. {
  7. "stat": "memory",
  8. "data": 8,
  9. "memory": 8
  10. },
  11. {
  12. "stat": "cpu",
  13. "data": 4,
  14. "cpu": 4
  15. }
  16. ]
  17. },
  18. {
  19. "id": "2",
  20. "properties": [
  21. {
  22. "stat": "status",
  23. "data": 0,
  24. "status": 0
  25. },
  26. {
  27. "stat": "cpu",
  28. "data": 4,
  29. "cpu": 4
  30. }
  31. ]
  32. }
  33. ]
  34. }

我已经尝试用JsonPath库做了以下事情,但对我来说,这是一个丑陋的解决方案,因为我将解析json三次,我做了一些手动替换。

  1. val configuration = Configuration.builder().options(Option.DEFAULT_PATH_LEAF_TO_NULL, Option.ALWAYS_RETURN_LIST).build()
  2. val jsonContext5 = JsonPath.using(configuration).parse(jsonStr)
  3. val listData = jsonContext.read("$['values'][*]['properties'][*]['data']").toString
  4. .replace("[", "").replace("]", "").split(",").toList
  5. val listStat = jsonContext.read("$['values'][*]['properties'][*]['stat']").toString
  6. .replace("[", "").replace("]", "")
  7. .replace("\"", "").split(",").toList
  8. // Replacing values of "stat" by values of "data"
  9. jsonContext5.map("$['values'][*]['properties'][*]['stat']", new MapFunction() {
  10. var count = - 1
  11. override def map(currentValue: Any, configuration: Configuration): AnyRef = {
  12. count += 1
  13. listData(count)
  14. }
  15. })
  16. // replace field stat by its value
  17. for( count <- 0 to listStat.size - 1){
  18. val path = s"['values'][*]['properties'][$count]"
  19. jsonContext5.renameKey(path, "stat", s"${listStat(count)}")
  20. }

这是得到的结果

  1. {
  2. "values": [
  3. {
  4. "id": "1",
  5. "properties": [
  6. {
  7. "data": 8,
  8. "memory": "8"
  9. },
  10. {
  11. "data": 4,
  12. "cpu": "4"
  13. }
  14. ]
  15. },
  16. {
  17. "id": "2",
  18. "properties": [
  19. {
  20. "data": 0,
  21. "memory": "0"
  22. },
  23. {
  24. "data": 4,
  25. "cpu": "4"
  26. }
  27. ]
  28. }
  29. ]
  30. }

有没有更好的方法来达到这个效果?我试着用gson来做,但是它处理路径不好。
这是使用Gson的一种方法,但是我将丢失关于其他列的信息,因为我正在创建另一个json。

  1. val jsonArray = jsonObject.get("properties").getAsJsonArray
  2. val iter = jsonArray.iterator()
  3. val agreedJson = new JsonArray()
  4. while(iter.hasNext) {
  5. val json = iter.next().getAsJsonObject
  6. agreedJson.add(replaceCols(json))
  7. }
  8. def replaceCols(json: JsonObject) = {
  9. val fieldName = "stat"
  10. if(json.has(fieldName)) {
  11. val columnName = json.get(fieldName).getAsString
  12. val value: String = if (json.has("data")) json.get("data").getAsString else ""
  13. json.addProperty(columnName, value)
  14. }
  15. json
  16. }
ebdffaop

ebdffaop1#

像这样的怎么样?

  1. private static void statDup(final JSONObject o) {
  2. if (o.containsKey("properties")) {
  3. final JSONArray a = (JSONArray) o.get("properties");
  4. for (final Object e : a) {
  5. final JSONObject p = (JSONObject) e;
  6. p.put(p.get("stat"), p.get("data"));
  7. }
  8. } else {
  9. for (final Object key : o.keySet()) {
  10. final Object value = o.get(key);
  11. if (value instanceof JSONArray) {
  12. for (final Object e : (JSONArray) value) {
  13. statDup((JSONObject) e);
  14. }
  15. }
  16. }
  17. }
  18. }
展开查看全部
nkhmeac6

nkhmeac62#

使用Gson,您应该做的是创建一个表示初始JSON对象的基类。然后,将JSON对象加载到内存中,可以逐个加载,也可以全部加载,然后对每个对象进行必要的更改以包含您的更改。然后,如果在上一步中没有将这些更改Map到新类,则将其Map到新类,并将它们序列化到文件或其他存储中。

6kkfgxo0

6kkfgxo03#

这是一个类型安全的纯FP circe实现,使用circe-optics

  1. object CirceOptics extends App {
  2. import cats.Applicative
  3. import cats.implicits._
  4. import io.circe.{Error => _, _}
  5. import io.circe.syntax._
  6. import io.circe.parser._
  7. import io.circe.optics.JsonPath._
  8. val jsonStr: String = ???
  9. def getStat(json: Json): Either[Error, String] =
  10. root.stat.string.getOption(json)
  11. .toRight(new Error(s"Missing stat of string type in $json"))
  12. def getData(json: Json): Either[Error, Json] =
  13. root.data.json.getOption(json)
  14. .toRight(new Error(s"Missing data of json type in $json"))
  15. def setField(json: Json, key: String, value: Json) =
  16. root.at(key).setOption(Some(value))(json)
  17. .toRight(new Error(s"Unable to set $key -> $value to $json"))
  18. def modifyAllPropertiesOfAllValuesWith[F[_]: Applicative](f: Json => F[Json])(json: Json): F[Json] =
  19. root.values.each.properties.each.json.modifyF(f)(json)
  20. val res = for {
  21. json <- parse(jsonStr)
  22. modifiedJson <- modifyAllPropertiesOfAllValuesWith { j =>
  23. for {
  24. stat <- getStat(j)
  25. data <- getData(j)
  26. prop <- setField(j, stat, data)
  27. } yield prop
  28. } (json)
  29. } yield modifiedJson
  30. println(res)
  31. }
展开查看全部
xurqigkl

xurqigkl4#

Gene McCulley的前一个答案给出了一个使用Java和类net.minidev.json的解决方案,这个答案使用类Gson,用Scala编写。

  1. def statDup(o: JsonObject): JsonObject = {
  2. if (o.has("properties")) {
  3. val a = o.get("properties").getAsJsonArray
  4. a.foreach { e =>
  5. val p = e.getAsJsonObject
  6. p.add(p.get("stat").getAsString, p.get("data"))
  7. }
  8. } else {
  9. o.keySet.foreach { key =>
  10. o.get(key) match {
  11. case jsonArr: JsonArray =>
  12. jsonArr.foreach { e =>
  13. statDup(e.getAsJsonObject)
  14. }
  15. }
  16. }
  17. }
  18. o
  19. }
展开查看全部
xkftehaa

xkftehaa5#

您的任务是在JSON文件的每个属性下为每条记录添加一个新字段,使当前的stat值成为字段名,数据值成为新字段值。如果尝试用Java来做,代码会相当长。
建议你使用SPL,一个开源的Java包来完成它。编码将非常容易,你只需要一行:
| | A级|
| - -|- -|
| 一个|=json(json(file(“数据. json”).read()).值.运行(属性=属性.(([[“统计”,“数据”]|统计]|[~.数组()|数据]).record())))|
SPL提供了Java调用的JDBC驱动程序,只需将上面的SPL脚本存储为addfield.splx,在Java应用程序中调用存储过程时调用它即可:

  1. Class.forName("com.esproc.jdbc.InternalDriver");
  2. con= DriverManager.getConnection("jdbc:esproc:local://");
  3. st = con.prepareCall("call addfield()");
  4. st.execute();

相关问题