Norayr Sargsyan
Norayr Sargsyan

Reputation: 1868

Get jsonpath for nested elements without providng the parent with rest assured

I need to get the label all values as an array from this JSON with the rest assured

This is example JSON

{
  "additionalProp1": {
    "type": "FADE_IN",
    "applyType": "IN",
    "label": "string",
    "properties": [
      {
        "name": "string",
        "type": "NUMERIC",
        "elementType": "TEXT",
        "label": "string",
        "defaultValue": {},
        "displayOrder": 0,
        "required": true,
        "visible": true,
        "dataset": {
          "type": "string",
          "subtype": "string",
          "filter": "string"
        }
      }
    ]
  },
  "additionalProp2": {
    "type": "FADE_IN",
    "applyType": "IN",
    "label": "string",
    "properties": [
      {
        "name": "string",
        "type": "NUMERIC",
        "elementType": "TEXT",
        "label": "string",
        "defaultValue": {},
        "displayOrder": 0,
        "required": true,
        "visible": true,
        "dataset": {
          "type": "string",
          "subtype": "string",
          "filter": "string"
        }
      }
    ]
  },
  "additionalProp3": {
    "type": "FADE_IN",
    "applyType": "IN",
    "label": "string",
    "properties": [
      {
        "name": "string",
        "type": "NUMERIC",
        "elementType": "TEXT",
        "label": "string",
        "defaultValue": {},
        "displayOrder": 0,
        "required": true,
        "visible": true,
        "dataset": {
          "type": "string",
          "subtype": "string",
          "filter": "string"
        }
      }
    ]
  }
}

With jsonpath extractor it is *.label

but I need to extract the path with rest assured

.extract().path("*.label");

But it's not working, how can I write the JSON path for getting the needed array?

Upvotes: 0

Views: 2324

Answers (2)

Ilya Lapitan
Ilya Lapitan

Reputation: 1006

This query should work for you:

.extract().path("collect{it.value.label}");

Note: if you have 'label' field as optional (can be missed in response) there will be null elements in the output array.

Response:

{
    "additionalProp1": {
      "type": "FADE_IN",
      "applyType": "IN",
      "label": "label1"
    },
    "additionalProp2": {
      "type": "FADE_OUT",
      "applyType": "IN",
      "label": "label2"
    },
    "additionalProp5": {
      "type": "FADE_IN",
      "applyType": "IN"
    },
    "additionalProp3": {
      "type": "FADE_IN",
      "applyType": "IN",
      "label": "label3"
    },
    "additionalProp4": {
      "type": "FADE_IN",
      "applyType": "IN"
    }
  }

Query:

ArrayList<String> body = given().when().get("http://localhost:3000/response").then().extract().path("collect{it.value.label}");

Output:

[label1, label2, null, label3, null]

Upvotes: 3

Roberto Manfreda
Roberto Manfreda

Reputation: 2623

if I understand the question correctly you want to extract all the values related to a key. Correct me if I'm wrong.
I don't know how to do it using jsonPath but I can provide some code for you.
Maybe you're not interested doing it by code. But in case you want to do it programmatically or someone who reads the question is interested, you can achieve the result using recursion.
I used this method to do other stuff but I adapted it on your needs. You can see the original code if you want.

Anyway here's an example:

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        String payload = "<YOUR_JSON_PAYLOAD>";

        // Create A json Object
        JSONObject jsonObject = new JSONObject(payload);

        // Initialize a list where store objects
        List<Object> values = new ArrayList<>();

        // Recursively find values by specifying key
        getValuesByKey(values, jsonObject, "label");

        System.out.println(values.toString());
    }


    // recursive
    private static void getValuesByKey(final List<Object> collection, JSONObject jsonObject, String targetKey) {
        for (String key : jsonObject.keySet()) {
            // Our targets
            if (key.equals(targetKey) && (jsonObject.get(key) instanceof String
                    || jsonObject.get(key) instanceof JSONArray
                    || jsonObject.get(key) instanceof Number
                    || null == jsonObject.get(key))) {

                collection.add(jsonObject.get(key));
            } else if (jsonObject.get(key) instanceof JSONObject) {
                // Going through simple JSON Object
                JSONObject modObj = (JSONObject) jsonObject.get(key);

                if (null != modObj) {
                    getValuesByKey(collection, modObj, targetKey);
                }
            } else if (jsonObject.get(key) instanceof JSONArray) {
                // Going through simple JSONArrays
                JSONArray modArray = (JSONArray) jsonObject.get(key);
                
                for (int i = 0; i < modArray.length(); i++) {
                    JSONObject nextObj = modArray.optJSONObject(i);
                    if (null != nextObj) getValuesByKey(collection, nextObj, targetKey);
                }
            }
        }
    }
}

Running the code using your json payload I get the following output:
[string, string, string, string, string, string]


I slightly modified the payload, to verify the correct extraction of the values, as follows:

{
  "additionalProp1": {
    "type": "FADE_IN",
    "applyType": "IN",
    "label": "string0",
    "properties": [
      {
        "name": "string",
        "type": "NUMERIC",
        "elementType": "TEXT",
        "label": "string00",
        "defaultValue": {},
        "displayOrder": 0,
        "required": true,
        "visible": true,
        "dataset": {
          "type": "string",
          "subtype": "string",
          "filter": "string"
        }
      }
    ]
  },
  "additionalProp2": {
    "type": "FADE_IN",
    "applyType": "IN",
    "label": "string1",
    "properties": [
      {
        "name": "string",
        "type": "NUMERIC",
        "elementType": "TEXT",
        "label": "string11",
        "defaultValue": {},
        "displayOrder": 0,
        "required": true,
        "visible": true,
        "dataset": {
          "type": "string",
          "subtype": "string",
          "filter": "string"
        }
      }
    ]
  },
  "additionalProp3": {
    "type": "FADE_IN",
    "applyType": "IN",
    "label": "string2",
    "properties": [
      {
        "name": "string",
        "type": "NUMERIC",
        "elementType": "TEXT",
        "label": "string22",
        "defaultValue": {},
        "displayOrder": 0,
        "required": true,
        "visible": true,
        "dataset": {
          "type": "string",
          "subtype": "string",
          "filter": "string"
        }
      }
    ]
  }
}

producing this out:
[string0, string00, string2, string22, string1, string11]


You need the org.json library in order to make the code works:

<dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20201115</version>
</dependency>

Upvotes: 0

Related Questions