0

I'm trying to read contents of JSON arary in Java, and get each element as a JSON string. My attempts have failed.

Let's assume here is the base JSON:

{ "book": [ 
      { "category": "",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": ""
      },
      { "category": "fiction",
        "author": "",
        "title": "Sword of Honour",
        "price": "12.99"
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": "8.99"
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ]
}

And I iterate through the whole array, and need to get each element as JSON String (some properties can be empty). So first String would be:

{       "category": "",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": ""
}

What I did is this:

String response = Unirest.get(db).header("cache-control", "no-cache").asString().getBody();

            int length = JsonPath.read(response, "$.book.length()");
            System.out.println(length);
            for (int i = 0; i < length; i++) {
                String json = JsonPath.read(response, "$.book["+i+"]").toString();

                System.out.println("1111111\n"+json);

                process(json);
            }

But what I get is messy, and not the same string. It doesn't include "".

What is the solution?

Tina J
  • 4,983
  • 13
  • 59
  • 125
  • 1
    Have you tried this? -> https://stackoverflow.com/questions/1568762/accessing-members-of-items-in-a-jsonarray-with-java – mindmaster Feb 21 '19 at 17:21
  • well, that's not `JSONPath`. Prefer not to change library at this time. – Tina J Feb 21 '19 at 17:25
  • Hi there, you should provide some more context, there is a zillion different ways of reading a Json, so, please first start by showing us which library are you using (JsonPath ?) and what are you getting as a result (what is that you are calling messy). That will help us to identify your problem and help you better. fyi, I've never used this JsonPath before... – Jorge Campos Feb 21 '19 at 17:30
  • 1
    JSONPath was intuitve, so I used it so far. Well, the one @MiguelCruz suggested works, so no bother using JSONPath anymore! – Tina J Feb 21 '19 at 17:41
  • I just tested your code here and it does work as "expected". You are using a library that reads a json thus it will response a json like object therefore no need for the double quotes in the values. For instance if you add in your code `String json = JsonPath.read(response, "$.book["+i+"].category").toString()` it will print blank for the first one and fiction for all others... If you want it to actually print it as a new json object you need to provide a specific Configuration for your read method. Just learned about it reading the docs :) – Jorge Campos Feb 21 '19 at 17:53
  • Accessing a property works as you said. I need the *whole item* as a JSON object, just as it appears on the example. – Tina J Feb 21 '19 at 18:00
  • I will add an answer for you. – Jorge Campos Feb 21 '19 at 18:12

1 Answers1

2

As I mentioned in comments JsonPath will read a JSON object and return it like so. It will be like a HashMap with the types being defined by what was parsed. If you, as you mentioned, wants the values as a Json after extracting it you need to convert what was read back to a Json again:

public static void main(String[] args) {
    String response = "{ \"book\": [ " + 
            "      { \"category\": \"\"," + 
            "        \"author\": \"Nigel Rees\"," + 
            "        \"title\": \"Sayings of the Century\"," + 
            "        \"price\": \"\"" + 
            "      }," + 
            "      { \"category\": \"fiction\"," + 
            "        \"author\": \"\"," + 
            "        \"title\": \"Sword of Honour\"," + 
            "        \"price\": \"12.99\"" + 
            "      }," + 
            "      { \"category\": \"fiction\"," + 
            "        \"author\": \"Herman Melville\"," + 
            "        \"title\": \"Moby Dick\"," + 
            "        \"isbn\": \"0-553-21311-3\"," + 
            "        \"price\": \"8.99\"" + 
            "      }," + 
            "      { \"category\": \"fiction\"," + 
            "        \"author\": \"J. R. R. Tolkien\"," + 
            "        \"title\": \"The Lord of the Rings\"," + 
            "        \"isbn\": \"0-395-19395-8\"," + 
            "        \"price\": 22.99" + 
            "      }" + 
            "    ]" + 
            "}";
    int length = JsonPath.read(response, "$.book.length()");
    System.out.println(length);
    Configuration conf = Configuration.defaultConfiguration();

    Object document = Configuration.defaultConfiguration().jsonProvider().parse(response);

    for (int i = 0; i < length; i++) {
        String json = conf.jsonProvider().toJson(JsonPath.read(document, "$.book["+i+"]"));
        System.out.println(json);
        //process(json);
    }
}

This will output:

{"category":"","author":"Nigel Rees","title":"Sayings of the Century","price":""}
{"category":"fiction","author":"","title":"Sword of Honour","price":"12.99"}
{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":"8.99"}
{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}

I just learned about it in the Docs, using the Configuration to parse the json will make your code parse it just once. It could even be improved (to remove the int length stuff), but I will leave it up to you :)

Jorge Campos
  • 22,647
  • 7
  • 56
  • 87
  • 1
    Interesting! Yeah good solution. Although I already used the `org.json` library. – Tina J Feb 21 '19 at 18:24
  • 1
    No problem. The good thing about it was that I get to learn something new cheers :) – Jorge Campos Feb 21 '19 at 18:25
  • And as a side note, I really liked the way JsonPath handles it and provides ways to do predicates, groupings and stuff, its like Mongo in java code... I will do some performance tests on it and if it is good enough start using it from now on. – Jorge Campos Feb 21 '19 at 18:26
  • Yeah it's great for finding specific value inside a JSON. I wonder why they didn't consider `$.book[i]` returning an item's JSON! – Tina J Feb 21 '19 at 20:11
  • My best bet is that it was due to performance reasons... in order to understand the json you need to parse it into something (in their case mapping structure), therefore transform it into something else... in order to return an original portion of the json you have to convert it back so maybe would be easier to add a toJson method into the JsonPath class itself and therefore callable from read method as in `...read(...).toJson()` – Jorge Campos Feb 21 '19 at 20:28