使用Java(Jackson)读取JSON中嵌套键的值

时间:2022-08-30 13:43:41

I'm a new Java programmer coming from a background in Python. I have weather data that's being collected/returned as a JSON with nested keys in it, and I don't understand how pull the values out in this situation. I'm sure this question has been asked before, but I swear I've Googled a great deal and I can't seem to find an answer. Right now I'm using json-simple, but I tried switching to Jackson and still couldn't figure out how to do this. Since Jackson/Gson seem to be the most used libraries, I'd would love to see an example using one of those libraries. Below is a sample of the data, followed by the code I've written so far.

我是一名来自Python背景的新Java程序员。我有收集/返回的天气数据作为带有嵌套键的JSON,我不明白在这种情况下如何拉出值。我确定之前已经问过这个问题,但是我发誓我已经用Google搜索了很多内容,我似乎无法找到答案。现在我正在使用json-simple,但我尝试切换到Jackson,但仍然无法弄清楚如何做到这一点。由于Jackson / Gson似乎是最常用的库,我很乐意看到使用其中一个库的示例。下面是数据样本,然后是我到目前为止编写的代码。

{
    "response": {
        "features": {
            "history": 1
        }
     },
    "history": {
        "date": {
            "pretty": "April 13, 2010",
            "year": "2010",
            "mon": "04",
            "mday": "13",
            "hour": "12",
            "min": "00",
            "tzname": "America/Los_Angeles"
        },
        ...
    }
}

Main function

主功能

public class Tester {

    public static void main(String args[]) throws MalformedURLException, IOException, ParseException {
        WundergroundAPI wu =  new WundergroundAPI("*******60fedd095");

        JSONObject json = wu.historical("San_Francisco", "CA", "20100413");

        System.out.println(json.toString());
        System.out.println();
        //This only returns 1 level. Further .get() calls throw an exception
        System.out.println(json.get("history"));
    }
}

The function 'historical' calls another function that returns a JSONObject

函数'historical'调用另一个返回JSONObject的函数

public static JSONObject readJsonFromUrl(URL url) throws MalformedURLException, IOException, ParseException {

    InputStream inputStream = url.openStream();

    try {
        JSONParser parser = new JSONParser();
        BufferedReader buffReader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));

        String jsonText = readAll(buffReader);
        JSONObject json = (JSONObject) parser.parse(jsonText);
        return json;
    } finally {
        inputStream.close();
    }
}

4 个解决方案

#1


39  

With Jackson's tree model (JsonNode), you have both "literal" accessor methods ('get'), which returns null for missing value, and "safe" accessors ('path'), which allow you to traverse "missing" nodes. So, for example:

使用Jackson的树模型(JsonNode),你有两个“文字”访问器方法('get'),它为缺失值返回null,以及“安全”访问器('path'),它允许你遍历“丢失”节点。所以,例如:

JsonNode root = mapper.readTree(inputSource);
int h = root.path("response").path("history").getValueAsInt();

which would return the value at given path, or, if path is missing, 0 (default value)

这将返回给定路径的值,或者,如果缺少路径,则为0(默认值)

But more conveniently, you can just use JSON pointer expression:

但更方便的是,您可以使用JSON指针表达式:

int h = root.at("/response/history").getValueAsInt();

There are other ways too, and often it is more convenient to actually model your structure as Plain Old Java Object (POJO). Your content could fit something like:

还有其他方法,通常将结构实际建模为Plain Old Java Object(POJO)更方便。您的内容可能类似于:

public class Wrapper {
  public Response response;
} 
public class Response {
  public Map<String,Integer> features; // or maybe Map<String,Object>
  public List<HistoryItem> history;
}
public class HistoryItem {
  public MyDate date; // or just Map<String,String>
  // ... and so forth
}

and if so, you would traverse resulting objects just like any Java objects.

如果是这样,您将像任何Java对象一样遍历结果对象。

#2


1  

Check out Jackson's ObjectMapper. You can create a class to model your JSON then use ObjectMapper's readValue method to 'deserialize' your JSON String into an instance of your model class. And vice-versa.

查看Jackson的ObjectMapper。您可以创建一个类来为JSON建模,然后使用ObjectMapper的readValue方法将您的JSON String“反序列化”为模型类的实例。反之亦然。

#3


1  

Use Jsonpath

使用Jsonpath

Integer h = JsonPath.parse(json).read("$.response.repository.history", Integer.class);

整数h = JsonPath.parse(json).read(“$。response.repository.history”,Integer.class);

#4


0  

Try jpath API. It's xpath equivalent for JSON Data. You can read data by providing the jpath which will traverse the JSON data and return the requested value.

试试jpath API。它是JSON Data的xpath等价物。您可以通过提供将遍历JSON数据并返回所请求值的jpath来读取数据。

This Java class is the implementation as well as it has example codes on how to call the APIs.

这个Java类是实现,它有关于如何调用API的示例代码。

https://github.com/satyapaul/jpath/blob/master/JSONDataReader.java

https://github.com/satyapaul/jpath/blob/master/JSONDataReader.java

Readme -

自述 -

https://github.com/satyapaul/jpath/blob/master/README.md

https://github.com/satyapaul/jpath/blob/master/README.md

Example:

例:

JSON Data:

JSON数据:

{
    "data": [{
        "id": "13652355666_10154605514815667",
        "uid": "442637379090660",
        "userName": "fanffair",
        "userFullName": "fanffair",
        "userAction": "recommends",
        "pageid": "usatoday",
        "fanPageName": "USA TODAY",
        "description": "A missing Indonesian man was found inside a massive python on the island of Sulawesi, according to local authorities and news reports. ",
        "catid": "NewsAndMedia",
        "type": "link",
        "name": "Indonesian man swallowed whole by python",
        "picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
        "full_picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
        "message": "Akbar Salubiro was reported missing after he failed to return from harvesting palm oil.",
        "link": "http:\/\/www.usatoday.com\/story\/news\/nation-now\/2017\/03\/29\/missing-indonesian-man-swallowed-whole-reticulated-python\/99771300\/",
        "source": "",
        "likes": {
            "summary": {
                "total_count": "500"
            }
        },
        "comments": {
            "summary": {
                "total_count": "61"
            }
        },
        "shares": {
            "count": "4"
        }
    }]

}

Code snippet:

代码段:

String jPath = "/data[Array][1]/likes[Object]/summary[Object]/total_count[String]";

String value = JSONDataReader.getStringValue(jPath, jsonData);

#1


39  

With Jackson's tree model (JsonNode), you have both "literal" accessor methods ('get'), which returns null for missing value, and "safe" accessors ('path'), which allow you to traverse "missing" nodes. So, for example:

使用Jackson的树模型(JsonNode),你有两个“文字”访问器方法('get'),它为缺失值返回null,以及“安全”访问器('path'),它允许你遍历“丢失”节点。所以,例如:

JsonNode root = mapper.readTree(inputSource);
int h = root.path("response").path("history").getValueAsInt();

which would return the value at given path, or, if path is missing, 0 (default value)

这将返回给定路径的值,或者,如果缺少路径,则为0(默认值)

But more conveniently, you can just use JSON pointer expression:

但更方便的是,您可以使用JSON指针表达式:

int h = root.at("/response/history").getValueAsInt();

There are other ways too, and often it is more convenient to actually model your structure as Plain Old Java Object (POJO). Your content could fit something like:

还有其他方法,通常将结构实际建模为Plain Old Java Object(POJO)更方便。您的内容可能类似于:

public class Wrapper {
  public Response response;
} 
public class Response {
  public Map<String,Integer> features; // or maybe Map<String,Object>
  public List<HistoryItem> history;
}
public class HistoryItem {
  public MyDate date; // or just Map<String,String>
  // ... and so forth
}

and if so, you would traverse resulting objects just like any Java objects.

如果是这样,您将像任何Java对象一样遍历结果对象。

#2


1  

Check out Jackson's ObjectMapper. You can create a class to model your JSON then use ObjectMapper's readValue method to 'deserialize' your JSON String into an instance of your model class. And vice-versa.

查看Jackson的ObjectMapper。您可以创建一个类来为JSON建模,然后使用ObjectMapper的readValue方法将您的JSON String“反序列化”为模型类的实例。反之亦然。

#3


1  

Use Jsonpath

使用Jsonpath

Integer h = JsonPath.parse(json).read("$.response.repository.history", Integer.class);

整数h = JsonPath.parse(json).read(“$。response.repository.history”,Integer.class);

#4


0  

Try jpath API. It's xpath equivalent for JSON Data. You can read data by providing the jpath which will traverse the JSON data and return the requested value.

试试jpath API。它是JSON Data的xpath等价物。您可以通过提供将遍历JSON数据并返回所请求值的jpath来读取数据。

This Java class is the implementation as well as it has example codes on how to call the APIs.

这个Java类是实现,它有关于如何调用API的示例代码。

https://github.com/satyapaul/jpath/blob/master/JSONDataReader.java

https://github.com/satyapaul/jpath/blob/master/JSONDataReader.java

Readme -

自述 -

https://github.com/satyapaul/jpath/blob/master/README.md

https://github.com/satyapaul/jpath/blob/master/README.md

Example:

例:

JSON Data:

JSON数据:

{
    "data": [{
        "id": "13652355666_10154605514815667",
        "uid": "442637379090660",
        "userName": "fanffair",
        "userFullName": "fanffair",
        "userAction": "recommends",
        "pageid": "usatoday",
        "fanPageName": "USA TODAY",
        "description": "A missing Indonesian man was found inside a massive python on the island of Sulawesi, according to local authorities and news reports. ",
        "catid": "NewsAndMedia",
        "type": "link",
        "name": "Indonesian man swallowed whole by python",
        "picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
        "full_picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
        "message": "Akbar Salubiro was reported missing after he failed to return from harvesting palm oil.",
        "link": "http:\/\/www.usatoday.com\/story\/news\/nation-now\/2017\/03\/29\/missing-indonesian-man-swallowed-whole-reticulated-python\/99771300\/",
        "source": "",
        "likes": {
            "summary": {
                "total_count": "500"
            }
        },
        "comments": {
            "summary": {
                "total_count": "61"
            }
        },
        "shares": {
            "count": "4"
        }
    }]

}

Code snippet:

代码段:

String jPath = "/data[Array][1]/likes[Object]/summary[Object]/total_count[String]";

String value = JSONDataReader.getStringValue(jPath, jsonData);