Как получить ключ из ArrayList, вложенный в JSON, с помощью Groovy и изменить его значение

Мне нужно найти ключ quote.orderAttributes[0].attributeDetail.name и установить для него значение null или любое другое значение, которое я хочу. Мне нужно сделать это только для первого элемента в любом списке, поэтому выбор [0] в порядке. Я хочу иметь возможность использовать такой путь, как 'quote.orderAttributes.attributeDetail.name'. Но, учитывая количество времени, которое я потратил до сих пор, пожалуйста, сообщите о любых лучших подходах.

Вот Json:

{
  "source": "source",
  "orderId": null,
  "Version": null,
  "quote": {
    "globalTransactionId": "k2o4-6969-1fie-poef",
    "quoteStatus": "Not Uploaded",
    "events": {
      "eventDescription": "event description",
      "eventTypeName": "Event Type"
    },
    "someReport": {
      "acceptResultsFlag": "Y",
      "orderDate": "2017-06-14",
      "orderStatus": "string"
    },
    "anotherReport": {
      "id": 627311,
      "orderDate": "2017-06-14"
    },
    "attributes": [
      {
        "appliedFlag": "Y",
        "attributeDetail": {
          "name": "name1",
          "value": "value1"
        },
        "attributeName": "attribute1"
      },
      {
        "appliedFlag": "N",
        "attributeDetail": {
          "name": "name2",
          "value": "value2"
        },
        "attributeName": "attribute2"
      }
    ],
    "orderAttributes": [
      {
        "appliedFlag": "Y",
        "attributeDetail": {
          "name": "name3",
          "value": "value3"
        },
        "attributeName": "orderAttribute1"
      },
      {
        "appliedFlag": "N",
        "attributeDetail": {
          "name": "name4",
          "value": "value4"
        },
        "attributeName": "orderAttribute2"
      }
    ]
  }
}

Я знаю, что следующие работы работают, но требуют, чтобы я знал, какой объект (ы) является ArrayList, и указал его индексированный элемент [0]:

def input = new File("src/test/resources/ShortExample.json")
def json = new JsonSlurper().parse(input)
def option1 = json['quote']["attributes"][0]["attributeDetail"]["name"]
println option1

//or this 
//where csvData.fullPath = quote.orderAttributes.attributeDetail.name

def (tkn1, tkn2, tkn3, tkn4) = csvData.fullPath.tokenize('.')
def option2 = json["$tkn1"]["$tkn2"][0]["$tkn3"]["$tkn4"]
println option2

Я хотел бы иметь возможность:

def input = new File("src/test/resources/ShortExample.json")
def json = new JsonSlurper().parse(input)
def changeValueTo = null
def (tkn1, tkn2, tkn3, tkn4) = csvData.fullPath.tokenize('.')
json["$tkn1"]["$tkn2"]["$tkn3"]["$tkn4"] = changeValueTo

Я пытался реализовать многие примеры здесь, используя рекурсию, методы, создающие MapsOrCollections, которые определяют, что представляет собой объект, а затем ищут его по ключу или значению, даже примеры батута.

Если бы вы могли указать мне на хорошую статью, объясняющую сериализацию и десериализацию, я бы тоже был очень признателен.

Заранее спасибо.


person SleepyD    schedule 03.10.2017    source источник
comment
Вы не можете избежать явного attributes[0], потому что просто произнесение attributes также является допустимой ссылкой, но на весь список объектов. Когда вы явно говорите attributes[0], вы указываете на определенный элемент этого списка.   -  person Szymon Stepniak    schedule 04.10.2017


Ответы (2)


как вариант:

import groovy.json.*;

def json = '''{
  "source": "source",
  "orderId": null,
  "Version": null,
  "quote": {
    "globalTransactionId": "k2o4-6969-1fie-poef",
    "quoteStatus": "Not Uploaded",
    "attributes": [
      {
        "appliedFlag": "Y",
        "attributeDetail": {
          "name": "name1",
          "value": "value1"
        },
        "attributeName": "attribute1"
      },
      {
        "appliedFlag": "N",
        "attributeDetail": {
          "name": "name2",
          "value": "value2"
        },
        "attributeName": "attribute2"
      }
    ]}
  }'''

json = new JsonSlurper().parseText(json)

def jsonx(Object json, String expr){
    return Eval.me('ROOT',json, expr)
}

println jsonx(json, 'ROOT.quote.attributes[0].attributeDetail.name')
jsonx(json, 'ROOT.quote.attributes[0].attributeDetail.name = null')
println jsonx(json, 'ROOT.quote.attributes[0].attributeDetail.name')
person daggett    schedule 03.10.2017
comment
Идеально!! Я надеюсь, что многие зайдут на этот пост и проголосуют за ваш ответ. На этом сайте так много других вопросов, похожих на этот вопрос, но имеющих гораздо более сложные решения. Эвал для меня новинка. Отличный ответ!!! - person SleepyD; 04.10.2017

Вы можете напрямую обращаться к любому вложенному полю объекта JSON и изменять его, например.

json.quote.attributes[0].attributeDetail.name = null

Это возможно, потому что new JsonSlurper().parse(input) возвращает groovy.json.internal.LazyMap объект. Groovy позволяет вам получать доступ и изменять любые записи Map, используя запись через точку, например.

Map<String, Map<String, Integer>> map = [
    lorem: [ipsum: 1, dolor: 2, sit: 3]
]

println map.lorem.ipsum // Prints '1'
map.lorem.ipsum = 10
println map.lorem.ipsum // Prints '10'

Вы можете применить тот же подход к своему примеру, например.

import groovy.json.JsonSlurper

String input = '''{
  "source": "source",
  "orderId": null,
  "Version": null,
  "quote": {
    "globalTransactionId": "k2o4-6969-1fie-poef",
    "quoteStatus": "Not Uploaded",
    "events": {
      "eventDescription": "event description",
      "eventTypeName": "Event Type"
    },
    "someReport": {
      "acceptResultsFlag": "Y",
      "orderDate": "2017-06-14",
      "orderStatus": "string"
    },
    "anotherReport": {
      "id": 627311,
      "orderDate": "2017-06-14"
    },
    "attributes": [
      {
        "appliedFlag": "Y",
        "attributeDetail": {
          "name": "name1",
          "value": "value1"
        },
        "attributeName": "attribute1"
      },
      {
        "appliedFlag": "N",
        "attributeDetail": {
          "name": "name2",
          "value": "value2"
        },
        "attributeName": "attribute2"
      }
    ],
    "orderAttributes": [
      {
        "appliedFlag": "Y",
        "attributeDetail": {
          "name": "name3",
          "value": "value3"
        },
        "attributeName": "orderAttribute1"
      },
      {
        "appliedFlag": "N",
        "attributeDetail": {
          "name": "name4",
          "value": "value4"
        },
        "attributeName": "orderAttribute2"
      }
    ]
  }
}'''

def json = new JsonSlurper().parse(input.bytes)

assert json.quote.attributes[0].attributeDetail.name == 'name1'

json.quote.attributes[0].attributeDetail.name = null

assert json.quote.attributes[0].attributeDetail.name == null

Я надеюсь, что это помогает.

person Szymon Stepniak    schedule 04.10.2017