Pit
Pit

Reputation: 11

read json with timestamps as jsonobject keys

I am trying to log weather data for a university hydrological project using java. The data is formated as a json file in 5 minute intervals for the last 24 hours in the following way (example):

{
   "1482439800":{
      "hu":92,
      "te":-2.9,
      "dp":-4.5,
      "pr":1028.4,
      "pa":null,
      "ws":1.4,
      "wd":180
   },
   "1482440100":{
      "hu":92,
      "te":-2.9,
      "dp":-4.5,
      "pr":1028.4,
      "pa":null,
      "ws":1.4,
      "wd":180
   }
}

I have already tried to use the following code to access data from the json file:

private static String readUrl(String urlString) throws Exception {
        BufferedReader reader = null;
        try {
            URL url = new URL(urlString);
            reader = new BufferedReader(new InputStreamReader(url.openStream()));
            StringBuffer buffer = new StringBuffer();
            int read;
            char[] chars = new char[1024];
            while ((read = reader.read(chars)) != -1)
                buffer.append(chars, 0, read); 

            return buffer.toString();
        } finally {
            if (reader != null)
                reader.close();
        }
    }
    public static Object[][] getstation1(){
        Object[][] data = null;
        try {
            JSONObject json = new JSONObject(readUrl("http://netzwerk.wetter.com/api/stationdata/14091/24/"));
            Iterator keys = json.keys();
            while (keys.hasNext()) {
                Object key = keys.next();
                JSONObject value = json.getJSONObject((String) key);
                double hu = value.getDouble("hu");
                System.out.println(hu);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return data;
    }

This was somewhat successful as it returned data for humidity (hu) but in a seemingly random order.

Now for my question: How do I read the times and return them alongside the corresponding weather data from newest to oldest inside the Object[][]?

Any help is appreciated. Thank you.

Upvotes: 1

Views: 1207

Answers (2)

Pit
Pit

Reputation: 11

Thanks for the answer but in the end I decided to go a slightly simpler route. I retrieved all the key names, sorted them and then read the corresponding data key by key. And as I was getting frequent errors because of data being null I added protection for that as well (I need them as actual numbers).

public static Object[][] getstation1(){
        Object[][] data = null;
        try {
            JSONObject json = new JSONObject(readUrl("http://netzwerk.wetter.com/api/stationdata/14091/2/"));
            System.out.println("Fetching "+"http://netzwerk.wetter.com/api/stationdata/14091/2/");
            String[] times = json.getNames(json);
            Arrays.sort(times);
            data = new Object[times.length][8];
            for (int i = 0; i < times.length; i++){
                Date temp = new Date((long)Integer.parseInt(times[i])*1000);
                data[i][0] = temp;
                if (json.getJSONObject(times[i]).isNull("hu")){
                    data[i][1] = 0;
                } else {
                    data[i][1] = json.getJSONObject(times[i]).getDouble("hu");
                }   
                if (json.getJSONObject(times[i]).isNull("te")){
                    data[i][2] = 0;
                } else {
                    data[i][2] = json.getJSONObject(times[i]).getDouble("te");
                }   
                if (json.getJSONObject(times[i]).isNull("dp")){
                    data[i][3] = 0;
                } else {
                    data[i][3] = json.getJSONObject(times[i]).getDouble("dp");
                }   
                if (json.getJSONObject(times[i]).isNull("pr")){
                    data[i][4] = 0;
                } else {
                    data[i][4] = json.getJSONObject(times[i]).getDouble("pr");
                }   
                if (json.getJSONObject(times[i]).isNull("pa")){
                    data[i][5] = 0;
                } else {
                    data[i][5] = json.getJSONObject(times[i]).getDouble("pa");
                }   
                if (json.getJSONObject(times[i]).isNull("ws")){
                    data[i][6] = 0;
                } else {
                    data[i][6] = json.getJSONObject(times[i]).getDouble("ws");
                }   
                if (json.getJSONObject(times[i]).isNull("wd")){
                    data[i][7] = 0;
                } else {
                    data[i][7] = json.getJSONObject(times[i]).getDouble("wd");
                }                   
            }
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }       
        return data;
    }

Upvotes: 0

teppic
teppic

Reputation: 7286

A sorted map would be more appropriate than an Object[][].

Quickly:

TreeMap<String, Object> sorted = new TreeMap<>(json.toMap());

But that will sort alphanumerically (probably fine in your case as the timestamps are all the same length).

You could do a little more work to sort the results into a typed map:

TreeMap<Date, Map<String, Double>> byDate = json.toMap().entrySet().stream()
    .collect(Collectors.toMap(
        e -> new Date(Long.valueOf(e.getKey()) * 1000),
        e -> (Map) e.getValue(),
        (a, b) -> {throw new IllegalArgumentException("Duplicate key " + a);},
        TreeMap::new
    ));

If you really need an Object[][] you can remap your data once it's sorted:

Object[][] data = sorted.entrySet().stream().map(e -> new Object[] {e.getKey(), e.getValue()}).toArray(Object[][]::new);

Or consider using an object mapper like jackson or gson.

Upvotes: 1

Related Questions