2015-04-24 16 views
14

Jestem nowym programistą Java pochodzącym z tła w języku Python. Mam dane pogodowe, które są gromadzone/zwracane jako JSON z zagnieżdżonymi kluczami i nie rozumiem, jak wyciągnąć wartości w tej sytuacji. Na pewno zadawano mi to pytanie wcześniej, ale przysięgam, że bardzo googlowałem i nie mogę znaleźć odpowiedzi. W tej chwili używam json-simple, ale próbowałem przejść na Jacksona i nadal nie mogłem wymyślić, jak to zrobić. Ponieważ Jackson/Gson wydają się być najczęściej używanymi bibliotekami, chciałbym zobaczyć przykład używając jednej z tych bibliotek. Poniżej znajduje się próbka danych, a następnie kod, który napisałem do tej pory.Wartość odczytu zagnieżdżonego klucza w JSONie z Javą (Jackson)

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

Główną funkcją

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")); 
    } 
} 

Funkcja 'historyczne' wywołuje inną funkcję, która zwraca 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(); 
    } 
} 
+0

możliwy duplikat [Jak analizować JSON w Javie] (http://stackoverflow.com/questions/2591098/how-to-parse-json-in-java) – Bobulous

Odpowiedz

32

W modelu drzewa Jacksona (JsonNode) dostępne są zarówno "dosłowne" metody uzyskiwania dostępu ("get"), które zwraca null dla brakującej wartości, oraz "bezpieczne" akcesoria ("ścieżka"), które umożliwiają przechodzenie " brakujące "węzły". Tak więc, na przykład:

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

które zwracają wartość w danej ścieżki, lub, jeśli ścieżka brakuje, 0 (wartość domyślna)

Ale wygodniej, można po prostu użyć JSON wskaźnik wyrażenie:

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

Są też inne sposoby i często wygodniej jest modelować swoją strukturę jako Zwykły Stary Obiekt Java (POJO). Treści zmieściłoby coś takiego:

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 
} 

a jeśli tak, byś przemierzać wynikające obiektów Podobnie jak wszelkie obiekty Java.

+0

Dziękuję za odpowiedź. Czy mógłbyś wyjaśnić, jakie byłyby zalety strukturyzacji obiektu jako POJO? Szczerze mówiąc, jako nowy programista Java, przykład POJO jest całkowicie nieczytelny dla mnie. –

+1

Ponieważ Java jest statycznie wpisana, w przeciwieństwie do Pythona (a może bardziej tego samego), myślę, że model POJO pasuje bardziej naturalnie, ponieważ wtedy pracujesz na podstawowych obiektach Java i nie martwisz się o część JSON. Po prostu definiujesz obiekty do wyrównania z JSON, a biblioteka (Jackson, GSON) może konwertować z jednego na drugi. Jeśli tak, cała konstrukcja, manipulacja, zmiana danych odbywa się z POJO, a konwersja do/z JSON jest oddzielnym automatycznym krokiem serializacji. Niektórzy programiści uważają to za prostsze i bardziej naturalne, podczas gdy inni wolą bardziej dynamiczny dostęp do drzewa. Część tego idzie na preferencje, inni na przypadki. – StaxMan

+0

... Chciałbym mieć prosty przykład, ale myślę, że wiele usług REST (JAX-RS, DropWizard) może pokazać niektóre zalety użytkowania. Zasadniczo można wykluczyć całe istnienie JSON i/lub XML; wejście i wyjście jest w postaci obiektów. Myślę, że to jest główna korzyść. Ale jak powiedziałem, częścią tego jest kwestia gustu, osobistych preferencji. – StaxMan

1

Check out Jacksona ObjectMapper. Możesz utworzyć klasę do modelowania JSON, a następnie użyć metody readValue obiektu ObjectMapper w celu "deserializacji" łańcucha JSON w instancję klasy twojego modelu. I wzajemnie.

1

Zastosowanie Jsonpath

całkowita H = JsonPath.parse (JSON) .read ("$ response.repository.history." Integer.class);

0

Wypróbuj interfejs API jpath. Jest to równoważnik xpath dla danych JSON. Możesz odczytać dane, podając jpath, które będą przechodzić przez dane JSON i zwracać żądaną wartość.

Ta klasa Java jest implementacją, a także zawiera przykładowe kody wywoływania interfejsów API.

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

Readme -

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

przykład:

JSON danych:

{ 
    "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" 
     } 
    }] 

} 

Fragment kodu:

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

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