1

W/O using Hashmap or GSON. This is my first time parsing a nested array. I know how to parse a single array and JSON objects. I've looked at several threads on here and I'm basing my code on this one:

How to parse this nested JSON array in android

I'm parsing the following JSON data(pasted from Postman) from the following url. JSON structure pasted below.

https://api.tfl.gov.uk/Line/victoria/Route/Sequence/inbound?serviceTypes=Regular,Night

I want to return a list of 16 subway stations in sequential order; return "id":940GDCOELW" or "naptanId:940DFDDKLJ09" and "name":"Warren Street Underground Station" for all the stations. They are stored in both "stations"(non-sequential) and "stopPointSequences" arrays and also in "orderedLineRoutes". I started parsing "stopPointSequences", but I'm not sure how to add the data to the ArrayList. Error indicated above the code. Or, would it be easier to parse "orderedLineRoutes"? But is it possible to parse it by matching the name to the id? I'm not sure if every "name" is included in the array. The first part of "stopPointSequence" array pasted below. Thank you in advance.

    {
        "$type": "Tfl.Api.Presentation.Entities.RouteSequence, Tfl.Api.Presentation.Entities",
        "lineId": "victoria",
        "lineName": "Victoria",
        "direction": "inbound",
        "isOutboundOnly": false,
        "mode": "tube", 
        "lineStrings":[..];
         "stations":[..];
        "stopPointSequences":[
 {
            "$type": "Tfl.Api.Presentation.Entities.StopPointSequence, Tfl.Api.Presentation.Entities",
            "lineId": "victoria",
            "lineName": "Victoria",
            "direction": "inbound",
            "branchId": 0,
            "nextBranchIds": [],
            "prevBranchIds": [],
                "stopPoint": [
                    {
                        "$type": "Tfl.Api.Presentation.Entities.MatchedStop, Tfl.Api.Presentation.Entities",
                        "parentId": "HUBWHC",
                        "stationId": "940GZZLUWWL",
                        "icsId": "1000249",
                        "topMostParentId": "HUBWHC",
                        "modes": [
                            "tube"
                        ],
                        "stopType": "NaptanMetroStation",
                        "zone": "3",
                        "hasDisruption": true,
                         "lines": [{..}],
      "status": true,
                        "id": "940GZZLUWWL",
                        "name": "Walthamstow Central Underground Station",
                        "lat": 51.582965,
                        "lon": -0.019885
                    },
    ],
         "orderedLineRoutes": [
            {
                "$type": "Tfl.Api.Presentation.Entities.OrderedRoute, Tfl.Api.Presentation.Entities",
                "name": "Walthamstow Central  ↔  Brixton ",
                "naptanIds": [
                    "940GZZLUWWL",
                    "940GZZLUBLR",
                    "940GZZLUTMH",
                    "940GZZLUSVS",
                    "940GZZLUFPK",
                    "940GZZLUHAI",
                    "940GZZLUKSX",
                    "940GZZLUEUS",
                    "940GZZLUWRR",
                    "940GZZLUOXC",
                    "940GZZLUGPK",
                    "940GZZLUVIC",
                    "940GZZLUPCO",
                    "940GZZLUVXL",
                    "940GZZLUSKW",
                    "940GZZLUBXN"
                ],
                "serviceType": "Night"
            },
            {
                "$type": "Tfl.Api.Presentation.Entities.OrderedRoute, Tfl.Api.Presentation.Entities",
                "name": "Walthamstow Central  ↔  Brixton ",
                "naptanIds": [
                    "940GZZLUWWL",
                    "940GZZLUBLR",
                    "940GZZLUTMH",
                    "940GZZLUSVS",
                    "940GZZLUFPK",
                    "940GZZLUHAI",
                    "940GZZLUKSX",
                    "940GZZLUEUS",
                    "940GZZLUWRR",
                    "940GZZLUOXC",
                    "940GZZLUGPK",
                    "940GZZLUVIC",
                    "940GZZLUPCO",
                    "940GZZLUVXL",
                    "940GZZLUSKW",
                    "940GZZLUBXN"
                ],
                "serviceType": "Regular"          }]
    }},

JSONUTILS class:

     public static ArrayList<Stations> extractFeatureFromStationJson(String stationJSON) {
    // If the JSON string is empty or null, then return early.
    if (TextUtils.isEmpty(stationJSON)) {
        return null;
    }
    ArrayList<Stations> stations = new ArrayList<>();
    try {
        // Create a JSONObject from the JSON response string
        JSONObject baseJsonResponse = new JSONObject(stationJSON);
        JSONArray stopPointSequenceArrayList = baseJsonResponse.getJSONArray("stopPointSequences");
        if (stopPointSequenceArrayList != null) {
            for (int i = 0; i < stopPointSequenceArrayList.length(); i++) {
                JSONObject elem = stopPointSequenceArrayList.getJSONObject(i);
                if (elem != null) {
                    JSONArray stopPointArrayList = elem.getJSONArray("stopPoint");
                    if (stopPointArrayList != null) {
                        for (int j = 0; j < stopPointArrayList.length(); j++) ;
                        JSONObject innerElem = stopPointArrayList.getJSONObject(i);
                        if (innerElem != null) {
                            String idStation = "";
                            if (innerElem.has("id")) {
                                idStation = innerElem.optString(KEY_STATION_ID);
                            }
                            String nameStation = "";
                            if (innerElem.has("name")) {
                                nameStation = innerElem.optString(KEY_STATION_NAME);
                            }
        //Error                    stopPointSequenceArrayList.add(stopPointArrayList);
                        }
                    }
                }
            }
        }
        //Error
        Stations station = new Stations(idStation, nameStation);
        stations.add(station);

    } catch (JSONException e) {
        // If an error is thrown when executing any of the above statements in the "try" block,
        // catch the exception here, so the app doesn't crash. Print a log message
        // with the message from the exception.
        Log.e("QueryUtils", "Problem parsing stations JSON results", e);

    }
      // Return the list of stations
    return stations;

}           
LeadBox4
  • 83
  • 2
  • 11

1 Answers1

1

There is couple errors inside your code so this should work now. You can now extract id and name values:

      try {
         ArrayList<Stations> stations = new ArrayList<>();

        // Create a JSONObject from the JSON response string
        JSONObject baseJsonResponse = new JSONObject(stationJSON);
        JSONArray stopPointSequenceArrayList = baseJsonResponse.getJSONArray("stopPointSequences");
        if (stopPointSequenceArrayList != null) {
            for (int i = 0; i < stopPointSequenceArrayList.length(); i++) {
                JSONObject elem = stopPointSequenceArrayList.getJSONObject(i);
                if (elem != null) {
                    JSONArray stopPointArrayList = elem.getJSONArray("stopPoint");
                    if (stopPointArrayList != null) {
                        for (int j = 0; j < stopPointArrayList.length(); j++) {
                            JSONObject innerElem = stopPointArrayList.getJSONObject(i);
                            if (innerElem != null) {
                                String id = innerElem.getString("id");
                                String name = innerElem.getString("name");
                                Log.d("Element", name);
                                Log.d("Element", id);
                                Stations station = new Stations(id, name);
                                stations.add(station);
                            }
                        }
                    }
                }
            }
         return stations;
        }
     return null; //something went wrong

    } catch (Exception e) {
        // If an error is thrown when executing any of the above statements in the "try" block,
        // catch the exception here, so the app doesn't crash. Print a log message
        // with the message from the exception.
        Log.e("QueryUtils", "Problem parsing stations JSON results", e);
        return null; // something went wrong exception is thrown

    }
Yupi
  • 4,402
  • 3
  • 18
  • 37
  • How would I return a list? I'm storing this arraylist in a RecyclerViewAdapter. Where do I put this code? Stations station = new Stations(idStation, nameStation); stations.add(station); Can you please elaborate on this: JSONObject baseJsonResponse = new JSONObject(loadJSONFromAsset());? I forgot to mention that I'm parsing the Url in a separate class. Also, is it possible to extract all the names and link them with the corresponding ids from "orderedLineRoutes": [? Thank you for the very quick reply. – LeadBox4 Jan 08 '19 at 12:25
  • First create and instance of your `ArrayList` and than you need to create new `Stations` object in every loop iteration and give that object values and store that object in `ArrayList`. I have updated the code, check now. – Yupi Jan 08 '19 at 12:30
  • What about this line?return stations; – LeadBox4 Jan 08 '19 at 12:38
  • @LeadBox4 you will `return stations` list after your loop finishes. If something went wrong and data is not downloaded you can `return null` but *remember* to check are `stations` list `null` before passing to adapter to prevent possible `crash` .Code updated. – Yupi Jan 08 '19 at 12:42
  • Why can't I return stations below the catch(Exception e)? – LeadBox4 Jan 08 '19 at 12:52
  • @LeadBox4 you can do that as well. – Yupi Jan 08 '19 at 12:53
  • Can you please move this discussion to chat? I don't have enough points yet. – LeadBox4 Jan 08 '19 at 12:58
  • This doesn't work: Stations station = new Stations(id, name); stations.add(station); – LeadBox4 Jan 08 '19 at 13:18
  • @LeadBox4 that should work if you have `Stations` class set correctly. – Yupi Jan 08 '19 at 13:45
  • I'll check. Can you please elaborate on the following? So, I need "return null" twice? Also, can you look at my question in the op about orderedLineRoutes? – LeadBox4 Jan 08 '19 at 14:11
  • Stations station = new Stations(idStation, nameStation); I checked Stations class. Everything should be working. However, now the error message is: 'Stations(android.os.Parcel) has protected access. Is it because this code is within a nested array? I've never seen this error message before when parsing. Thank you again. – LeadBox4 Jan 08 '19 at 15:21
  • @LeadBox4 if you have code somewhere accessible for example on git (Github, Bitbucket, Gitlab) I could take a look. – Yupi Jan 08 '19 at 15:51
  • Thank you. Can I follow you on Github? https://github.com/Annin7y/LondonTubeSchedule/tree/master/app/src/main/java/capstone/my/annin/londontubeschedule Also, can you please move this discussion to chat? – LeadBox4 Jan 08 '19 at 16:28
  • @LeadBox4 change your access of your `protected static final Creator CREATOR` to `public static final Creator CREATOR` than create an empty constructor in `Stations` class `public Stations(){ }` and than you can do like this in your `JSONUtils` class: `Stations station = new Stations(); station.setStationId(idStation); station.setStationName(nameStation); stations.add(station);` – Yupi Jan 08 '19 at 18:21
  • But why is this message appearing? Is it because of the nested array? Is there another way to parse this? Thank you. – LeadBox4 Jan 08 '19 at 22:30
  • @LeadBox4 Because you declared `Creator CREATOR` as `protected` instead should be `public` in your scenario. – Yupi Jan 08 '19 at 22:43
  • Yes, I know. But when parsing non-nested array Creator is always protected. Again, this is my first time parsing a nested array. So, that's why it has to be public? P.S. Are you allowed to move this discussion to chat? – LeadBox4 Jan 08 '19 at 22:45
  • Parsing works. Now, only two to a few stations are being downloaded. How can I debug to check why the entire list isn't being downloaded? Thank you in advance. – LeadBox4 Jan 09 '19 at 04:06
  • Thank you again for your answers. I started a new thread about the data not fully downloading. If you have time, can you please take a look? – LeadBox4 Jan 10 '19 at 10:13