Доступ к элементам jsonpath с вложенными объектами

Я хочу извлечь определенные значения из пути массивов и объектов JSON и использовать эти значения для дальнейшей обработки, и я изо всех сил пытаюсь получить доступ к этим элементам. Вот ответ JSON:

[  
 {  
  "od_pair":"7015400:8727100",
  "buckets":[  
     {  
        "bucket":"C00",
        "original":2,
        "available":2
     },
     {  
        "bucket":"A01",
        "original":76,
        "available":0
     },
     {  
        "bucket":"B01",
        "original":672,
        "available":480
     }
    ]
    },
 {  
  "od_pair":"7015400:8814001",
  "buckets":[  
     {  
        "bucket":"C00",
        "original":2,
        "available":2
     },
     {  
        "bucket":"A01",
        "original":40,
        "available":40
     },
     {  
        "bucket":"B01",
        "original":672,
        "available":672
     },
     {  
        "bucket":"B03",
        "original":632,
        "available":632
     },
     {  
        "bucket":"B05",
        "original":558,
        "available":558
     }
    ]
 }
]

Я попытался получить доступ к корневым элементам с помощью $, но не смог продвинуться дальше.

Вот метод тестирования, который я написал. Я хочу извлечь значение для od_pair, и в каждой od_pair мне нужно получить коды сегментов и их доступные номера.

public static void updateBuckets(String ServiceName, String DateOfJourney) throws Exception {
    File jsonExample = new File(System.getProperty("user.dir"), "\\LogAvResponse\\LogAvResponse.json");
    JsonPath jsonPath = new JsonPath(jsonExample);

    List<Object> LegList = jsonPath.getList("$");
    // List<HashMap<String, String>> jsonObjectsInArray = jsonPath.getList("$");

    int NoofLegs = LegList.size();
    System.out.println("No of legs :" + NoofLegs);
    for (int j = 0; j <= NoofLegs; j++)
    // for (HashMap<String, String> jsonObject : jsonObjectsInArray) {
    {

        String OD_Pair = jsonPath.param("j", j).getString("[j].od_pair");
        // String OD_Pair = jsonObject.get("od_pair");

        System.out.println("OD Pair: " + OD_Pair);
        List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");

        int NoOfBuckets = BucketsList.size();
        // System.out.println("OD Pair: " + OD_Pair);
        System.out.println("no of Buckets: " + NoOfBuckets);

        for (int i = 0; i < NoOfBuckets; i++) {
            String BucketCode = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].bucket");
            String Available = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].available");

            int BucketCodeColumn = XLUtils.getBucketCodeColumn(BucketCode);
            int ServiceRow = XLUtils.getServiceRow(ServiceName, DateOfJourney, OD_Pair);
            System.out.println("Row of " + ServiceName + ":" + DateOfJourney + "is:" + ServiceRow);
            System.out.println("Bucket Code column of " + BucketCode + " is: " + BucketCodeColumn);
            XLUtils.updateAvailability(ServiceRow, BucketCodeColumn, Available);
        }
    }

}

}

Это ошибка, которую я вижу:

Caused by: 
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup 
failed:
Script1.groovy: 1: unexpected token: [ @ line 1, column 27.
restAssuredJsonRootObject.[j].od_pair

Может кто-то мне помочь, пожалуйста?

I need to be able to retrieve the bucket codes and their available numbers. На основе od_pair, верно?
Fenio 30.07.2019 15:12

Я хочу иметь доступ не только к od_pair, но и к объектам ведра внутри. Таким образом, каждая od_pair имеет множество сегментов в качестве объектов. С вашим решением Hashmap я не уверен, как я могу связаться с различными сегментами в каждой od_pairs

Mihir 30.07.2019 15:12

Да, это правильно @Fenio

Mihir 30.07.2019 15:12

Хорошо, понял. Есть несколько решений, но я покажу вам расширенное и лучшее (на мой взгляд). мне нужно несколько минут

Fenio 30.07.2019 15:13

@Fenio: Итак, в основном я пытаюсь запустить вложенные циклы for, один для получения od_pair, а внутри него цикл for для сегментов, чтобы получить код каждого сегмента и доступный номер. Извините, поскольку я новичок, и поэтому некоторые из моих вопросов могут показаться здесь наивными.

Mihir 30.07.2019 15:14

Не извиняйтесь за вопросы. Просто убедитесь, что люди понимают, что вы хотите сделать, и приложите усилия :)

Fenio 30.07.2019 15:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
3 534
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я бы предложил разобрать ваш JSON на классы Java, чтобы облегчить обработку.

Как это сделать? Во-первых, нам нужно создать классы Java, которые будут представлять предоставленный вами JSON.

Давайте проанализируем JSON. Начинается с массива. Массив содержит несколько объектов JSON. Эти объекты содержат значение od_pair и массив объектов с именем buckets.

Давайте создадим класс (вы можете назвать его как хотите) Pair

public class Pair {
    public String od_pair; //this name is important because it corresponds with the json element's name!
    public List<BucketObject> buckets; //same here!
}

Этот класс представляет один объект JSON в основном массиве. Он содержит od_pair значение И вложенный массив JSON, но в представлении Java -> Список BucketObject классов. Давайте создадим класс BucketObject:

public class BucketObject { //this name is NOT importnat
    public String bucket; //names are important
    public int original;
    public int available;
}

У нас есть только 3 значения в каждом из объектов.

Теперь пришло время разобрать JSON на письменные классы.

JsonPath path = JsonPath.from(json);
Pair[] pairs = path.getObject("$", Pair[].class);

Помните, что Pair — это один объект JSON. Вот почему мы начинаем синтаксический анализ с корня, представленного знаком доллара $, и объявляем, что JSON следует анализировать в МАССИВ Pair объектов!

Теперь обработка будет намного проще!

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

Итак, у нас есть массив класса Pair: Pair[] pairs;

Теперь мы хотим получить 1 объект Pair на основе значения od_pair.

    public static Pair getPairBasedOnOdPairValue(Pair[] pairs, String odPairValue) {
        for (Pair pair : pairs) {
            if (pair.od_pair.equals(odPairValue)) return pair;
        }

        throw new NoSuchElementException();
    }

Теперь у нас есть объект Pair. Мы можем получить доступ к buckets для этого объекта, используя

List<BucketObject> buckets = pair.buckets;

Остальная часть обработки — это повторение List<BucketObject> и получение желаемых значений.

Надеюсь, поможет!

Большое спасибо @Fenio, я реализую этот подход и сообщу, как он идет.

Mihir 30.07.2019 15:37

@Mihir Если у вас больше проблем - создайте еще один вопрос. Я регулярно просматриваю вопросы с пометкой rest assured :)

Fenio 30.07.2019 15:38

Хорошо, обязательно сделаю @Fenio. Большое тебе спасибо

Mihir 30.07.2019 15:39

Большое спасибо за ваше решение. просто для моего понимания и обучения, не могли бы вы также посоветовать код цикла for, который я написал ранее. Где я вложил один цикл for для получения od_pair и один для получения информации о сегменте, пожалуйста? Что я там упустил или где я ошибся? @Фенио

Mihir 30.07.2019 18:01

@Mihir завтра проверю

Fenio 30.07.2019 19:53

@Mihir Я добавил некоторые пояснения во второй ответ. Я не могу просто указать, где вы ошиблись, но, надеюсь, вы сможете исправить это самостоятельно.

Fenio 31.07.2019 07:19

Создал новый вопрос по этому поводу в - stackoverflow.com/questions/57288085/… @Fenio

Mihir 31.07.2019 11:59

Мне удалось решить проблему в stackoverflow.com/questions/57288085/…. Я тоже добавил решение. Спасибо за вашу помощь :) @Fenio

Mihir 31.07.2019 13:18

ОП попросил меня посоветовать, как исправить его код, отсюда и второй ответ.

Давайте проанализируем код, который вы предоставили:

public static void updateBuckets(String ServiceName, String DateOfJourney) throws Exception {
    File jsonExample = new File(System.getProperty("user.dir"), "\\LogAvResponse\\LogAvResponse.json");
    JsonPath jsonPath = new JsonPath(jsonExample);

    List<Object> LegList = jsonPath.getList("$");
    // List<HashMap<String, String>> jsonObjectsInArray = jsonPath.getList("$");

    int NoofLegs = LegList.size();
    System.out.println("No of legs :" + NoofLegs);
    for (int j = 0; j <= NoofLegs; j++)
    // for (HashMap<String, String> jsonObject : jsonObjectsInArray) {
    {

        String OD_Pair = jsonPath.param("j", j).getString("[j].od_pair");
        // String OD_Pair = jsonObject.get("od_pair");

        System.out.println("OD Pair: " + OD_Pair);
        List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets");

        int NoOfBuckets = BucketsList.size();
        // System.out.println("OD Pair: " + OD_Pair);
        System.out.println("no of Buckets: " + NoOfBuckets);

        for (int i = 0; i < NoOfBuckets; i++) {
            String BucketCode = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].bucket");
            String Available = jsonPath.param("j", j).param("i", i).getString("[j].buckets[i].available");

            int BucketCodeColumn = XLUtils.getBucketCodeColumn(BucketCode);
            int ServiceRow = XLUtils.getServiceRow(ServiceName, DateOfJourney, OD_Pair);
            System.out.println("Row of " + ServiceName + ":" + DateOfJourney + "is:" + ServiceRow);
            System.out.println("Bucket Code column of " + BucketCode + " is: " + BucketCodeColumn);
            XLUtils.updateAvailability(ServiceRow, BucketCodeColumn, Available);
        }
    }

}

Сейчас я не использую компилятор, поэтому могу кое-что упустить.

#1

Первое, что я вижу, это то, что вы сохраняете основной массив в List<Object>List<Object> LegList = jsonPath.getList("$");

Вместо этого вы можете сохранить его в более понятном виде, поскольку Object настолько универсален, что вы понятия не имеете, что у него внутри.

List<HashMap<String, Object>> LegList = jsonPath.getList("$");

#2 Цикл for выглядит неправильно из-за оценщика j <= NoofLegs;. Это, вероятно, вызовет IndexArrayOutOfBoundsException или что-то подобное. С данным кодом, если у вас есть 4 ноги, цикл for попытается обработать 5 ног, которые неверны.

#3 Аналогично строке № 1, в которой вы сохраняете список сегментов. List<Object> BucketsList = jsonPath.param("j", j).getList("[j].buckets"); Вместо этого также можно изменить на List<HashMap<String, Object>>.

Если бы вы сделали это, вам не понадобился бы вложенный цикл for на основе целых чисел.

Видите ли, HashMap<String, Object> на самом деле имеет решающее значение для разбора вложенных объектов. Строка — это просто имя, например buckets или od_pair. Это представление JSON. Второй аргумент Object отличается. RestAssured возвращает разные типы в HashMap, поэтому мы используем Object вместо String. Иногда это не String.

Пример на основе вашего JSON:

Соберите ведра в список HashMaps:

List<HashMap<String, Object>> bucketsList = jsonPath.param("j", j).getList("[j].buckets");

Каждый из HashMap в списке является представлением этого:

{  
        "bucket":"C00",
        "original":2,
        "available":2
},

Object в HashMap в вашем случае либо String, либо Integer. Итак, если вы получите элемент bucket из HashMap, вы получите его значение.

Давайте объединим это с циклом for для дальнейшего уточнения:

List<HashMap<String, Object>> bucketsList = jsonPath.param("j", j).getList("[j].buckets");
for (HashMap<String, Object> singleBucket : bucketsList) {
    String firstValue = (String) singleBucket.get("bucket");
    Integer secondValue = (Integer) singleBucket.get("original");
}

Большое спасибо за объяснение. Ваше объяснение очень ясное и помогает понять это так хорошо. Большое спасибо за вашу помощь, сэр!

Mihir 31.07.2019 09:17

@Mihir Добро пожаловать :) Не стесняйтесь задавать дополнительные вопросы, если вам нужна помощь.

Fenio 31.07.2019 10:47

Мне понравился этот вышеприведенный подход, который вы предоставили. У меня только один вопрос по этому поводу. Я снова добавил раздел ниже. Пожалуйста, ответьте. @Fenio

Mihir 31.07.2019 11:43

Глядя на сообщение об ошибке, похоже, что вы используете Будьте уверены и что класс JsonPathio.restassured.path.json.JsonPath из надежной библиотеки.

Я уверен, что вы знаете, но (возможно, для других читателей) обратите внимание, что это отличается от json-путь Jayway и НЕ является классом com.jayway.jsonpath.JsonPath из этой библиотеки.

Также имейте в виду, что, как упоминалось в документация rest-assured, используется синтаксис Groovy-GPath для манипулирования/извлечения JSON.

При этом я считаю, что следующее извлечет то, что вам нужно, то есть od_pair и соответствующие им сегменты с доступными номерами:

Map<String, Map<String, Integer>> map = JsonPath.with(jsonString).get("collectEntries{entry -> [entry.od_pair, entry.buckets.collectEntries{bucketEntry -> [bucketEntry.bucket, bucketEntry.available]}]}");

где для каждой записи карты ключ — это od_pair, а значение — это другая карта, ключом которой является ведро, а значением — доступный номер. jsonString — это JSON, который вы указали в вопросе.

Вы можете перебирать карту, чтобы получить то, что хотите:

for(Map.Entry<String, Map<String, Integer>> entry : map.entrySet())
{
    String od_pair = entry.getKey();

    Map<String, Integer> bucketMap = entry.getValue();

    for(Map.Entry<String, Integer> bucketEntry : bucketMap.entrySet())
    {
        String bucket = bucketEntry.getKey();
        int available = bucketEntry.getValue();
    }
}

Распечатав карту вы получите:

{7015400:8727100 = {C00=2, A01=0, B01=480}, 7015400:8814001 = {C00=2, A01=40, B01=672, B03=632, B05=558}}

Печать карты в формате JSON с использованием Gson:

System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(map));

ты получишь

{
  "7015400:8727100": {
    "C00": 2,
    "A01": 0,
    "B01": 480
  },
  "7015400:8814001": {
    "C00": 2,
    "A01": 40,
    "B01": 672,
    "B03": 632,
    "B05": 558
  }
}

Для фона строка collectEntries{entry -> [entry.od_pair, entry.buckets.collectEntries{bucketEntry -> [bucketEntry.bucket, bucketEntry.available]}]}

представляет собой замыкание Groovy, использующее методы из API коллекций Groovy: см. Коллекция, Список и карта.

Спасибо @Fenio за чистое Java-решение, описанное выше.

Другие вопросы по теме