简体   繁体   中英

How to read complex JSON string with variable array depth and structure?

I have a lot of JSON data which is organized in nested lists. Each list consists of other lists and those lists could contain other lists and so on. The deepest list consists of a pair of longitute and latitude, eg

[[[.....[16.353542354,48.2354242424],[16.46353535,48.2546754646]....].....].

It would look as graph like this:

Coord列表

I basically don't know how nested those lists are. They differ all the time. The next difficult part is that I need to get "coordinate polygons" from it. That means that the lists that only consist of pairs of coordinates belong to the same polygon. For example:

[......[[16.23542424,48.2342424242],[16.2423242352354,48.12342534634],[16.35353453535,48.345635353]]......

This would mean that there is a polygon consisting of 3 pairs of coordinates (so 3 corners). I'm sure that this is solvable with some kind of String parsing. I wonder if this is possible with basic JSON.simple (or maybe any other API) possibilities. The problem is that JSON doesn't know anything about the data it is parsing. I have to tell JSON what the object is and have to use type conversion to get the correct data. See these examples here . Now I need the other way around, but I never know what type is the data ("is it still another list or is the data the pair of coordiantes") , because those lists are very dynamic. How can this be done in a convenient way? I could write some string parsing algorithm with some "push and pop behavior" to compare the JSON string character by character, but I wonder if there isn't a better way to do this?

[UPDATE]
I figured out that this is a standardized JSON format, called GeoJSON. If you know how to read the data, it's pretty clear. A Multipolygon consists of Polygons, and Polygons can have holes, represented by a 2nd Array in a Polygon object. See spec: Polygon , Multipolygon

I basically don't know how nested those lists are

You know exactly how deeply nested these lists are. At the top of your json, you have:

"type": "Multipolygon"

To me, that implies List<Polygon> . Now, what's a Polygon ? Well, that's obviously a List<Coordinate> . Finally, we know a Coordinate is a list with two elements.

To conclude, we have List<List<List<double>>> . The depth of the arrays is known.

class Location {
    private double _lat;
    private double _long;

    public Location(double lat, double long) { _lat = lat; _long = long }

    public static Location fromJSONArray(JSONArray json) {
        int n = json.length();
        if(n != 2) throw new IllegalArgumentException('json');

        return new Location(json.getDouble(0), json.getDouble(1));
    }
}
class Polygon : List<Location> {
    public static Polygon fromJSONArray(JSONArray json) {
        int n = json.length();
        Polygon p = new Polygon();
        for(int i = 0; i < n; i++) {
            p.add(Location.fromJSONArray(json.getJSONArray(i)));
        }
        return polygon;
    }
}

private List<Polygon> parseLists(JSONArray nestedList) throws JSONException
{
    List<Polygon> polygons = new ArrayList<Polygon>();
    int n = json.length();
    for(int i = 0; i < n; i++) {
        polygons.add(Polygon.fromJSONArray(json.getJSONArray(i)));
    }
    return polygons;
}

What language are looking to parse JSON with. Theoretically the idea can apply in most languages. If its javascript you can use

  for(var key in myJSONObjectVariable){
       var current = myJSONObjectVariable[key];
       //Have some logic or inner loops taking place on current
  }

Depending on how unpredictable the JSON data is however, I think you may be right though. String parsing may be the way to go however

You have multiple issues here, so I would first suggest you break down the problem into steps.

Step 1, you need to somehow get to a distinct list somewhere in your nesting.

You don't mention what programming language you are using so the answer to that problem will vary. If you are doing this directly in JavaScript then accessing any distinct list is a simple data access:

geometry.coordinates[0][1]

or as a Java map of lists (no error checking for null returns or invalid array indexes, just an example)

geometry.get("coordinates").get(0).get(1)      

If you are using Java or C++ or something like that, you may find it easier to use a JSON library and convert the data into a language appropriate structure, a map of vectors for example. I would not attempt to manipulate the JSON string directly.

Then, once you have the ability to fetch the data contents in a language appropriate manner, step 2 would be to evaluate what you retrieve against your rules and determine what type of data it is you retrieved.

The following code would recursively extract the latitude and longitude values at any depth into resultantArray , using the JSON Java library (the jar can be downloaded from here ):

public void run() throws JSONException
{
    JSONArray nestedList =
        new JSONArray("[" + "[ 1, 2 ]," + "[ [ 1, 2 ], [ 1, 2 ], [ 1, 2 ] ]," + "[ 3, 4 ],"
            + "[ [ [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ] ], [ 1, 2 ], [ 1, 2 ], [ 1, 2 ] ] ] ]");
    parseLists(nestedList);
}

private void parseLists(JSONArray nestedList) throws JSONException
{
    List<Location> resultantArray = new ArrayList<Location>();
    parseNestedList(nestedList, resultantArray);
    System.out.println(resultantArray.size());
}

private void parseNestedList(JSONArray json, List<Location> resultantArray) throws JSONException
{
    int elementCount = json.length();
    if (elementCount <= 0)
    {
        return;
    }
    if (json.get(0) instanceof JSONArray)
    {
        for (int i = 0; i < elementCount; i++)
        {
            parseNestedList((JSONArray) json.get(i), resultantArray);
        }
    }
    else
    {
        resultantArray.add(new Location(Double.parseDouble(json.get(0).toString()), Double.parseDouble(json
            .get(1)
            .toString())));
    }
}

Once that is done, you should run your algorithm to identify polygons considering the entries in the resultantArray as points.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM