JSON Response

This is a simple plugin that makes the server return a JSON representation of a dataset, combining its structure and attributes in a single response. You can install it using easy_install:

$ easy_install dap.responses.json

After installation, your server will return the JSON markup when acessing a URI with the extension .json (instead of .dds, e.g.). This is useful if you want to parse a dataset from Javascript when building rich web interfaces, for example.

Specification

The JSON response is a direct mapping of the DDS/DAS responses to a JSON object, describing both structure and attributes in a single representation. The response is a JSON object containing the JSON representation of the root dataset:

{ dataset }

The response should have the HTTP header:

Content-description: dods_json
XDODS-Server: dods/version
Content-type: application/json

The dataset representation is described below.

Dataset

A DAP Dataset is represented in the following way:

"name": { "type": "Dataset",
          "attributes": attributes,
          var0, var1, ..., varn
        }

Where name is the dataset name, attributes is a JSON description of the dataset attributes (described below), and var1varn is the JSON representation of the contained variables.

Structure

A DAP structure has the same representation as a dataset, with the type being defined as Structure as follows:

"name": { "type": "Structure",
          "attributes": attributes,
          var0, var1, ..., varn
        }

Sequence

A DAP sequence also has the same representation as a dataset, with the type being defined as Sequence as follows:

"name": { "type": "Sequence",
          "attributes": attributes,
          var0, var1, ..., varn
        }

Base type

Base DAP types have the following representation:

"name": { "type": "dap-type",
          "attributes": attributes
        }

Where dap-type is the string representation of the object type from the DDS response (String, Int32, etc.) and name is the variable name.

Array

The JSON representation of an array is simply the representation of the base object with a shape attribute:

"name": { "type": "base-type",
          "shape": [dim1, dim2, ..., dimn], 
          "attributes": attributes
        }

Here, base-type is a string from Grid, Sequence, Structure or, more commonly, a basic DAP type like Int32 or Float64. The variables dim1dimn are integers representing the size of each dimension of the array.

Grid

The DAP grid is represented in the following way:

"name": { "type": "Grid",
          "array": var,
          "maps": { "name1": var,
                    "name2": var,
                    ...
                    "namen": var
                  },
          "attributes": attributes
        }

Where the first var is the JSON representation of the grid array, and the others represent the maps.

Attributes

Attributes are represented simply as pairs of keys and values; type must be infered from the values. This is the JSON representation:

{ "name1": value | attributes,
  "name2": value | attributes,
  ...
  "namen": value | attributes }

Note that the attributes can be either values or nested attributes. The variable value can be a JSON string, number or list.

JSON response with data

Given the difficulty of writing a DODS parser in Javascript, the JSON response allows the transmission of the data together with the structure and attributes of the dataset. This is done optionally by the client by specifying the variable output_data in the query string as 1.

The response is given as a value or list (or nested list, for multidimensional variables) in the data attribute of base types. This includes arrays of base types and base types inside sequences.

Examples

Let's start with a simple dataset with the following DDS/DAS:

Dataset {
} test;
Attributes {
    NC_GLOBAL {
    }
    String author "Roberto De Almeida";
}

Here's the corresponding (indented for clarity) JSON response with the proper header:

Content-description: dods_json
XDODS-Server: dods/2.0
Content-type: application/json

{"test": {"attributes": {"NC_GLOBAL": {},
                         "author": "Roberto De Almeida"},
          "type": "Dataset"}}

Let's add a base type variable to the dataset, so we have:

Dataset {
    Int32 a;
} test;
Attributes {
    NC_GLOBAL {
    }
    String author "Roberto De Almeida";
    a {
    }
}

Now we have the following JSON response:

Content-description: dods_json
XDODS-Server: dods/2.0
Content-type: application/json

{"test": {"attributes": {"NC_GLOBAL": {},
                         "author": "Roberto De Almeida"},
          "type": "Dataset",
          "a": {"type": "Int32"}}}

Note that now the dataset test has a variable a of type Int32, without attributes. We can download the value of this variable by appending output_data=1 to the URL, giving us:

Content-description: dods_json
XDODS-Server: dods/2.0
Content-type: application/json

{"test": {"attributes": {"NC_GLOBAL": {},
                         "author": "Roberto De Almeida"},
          "type": "Dataset",
          "a": {"type": "Int32",
                "data": 42}}}

Let's make a an array of integers ranging from 0 to 9; here the new DDS:

Dataset {
    Int32 a[a = 10];
} test;

And the JSON representation, with data:

Content-description: dods_json
XDODS-Server: dods/2.0
Content-type: application/json

{"test": {"attributes": {"NC_GLOBAL": {},
                         "author": "Roberto De Almeida"},
          "type": "Dataset",
          "a": {"type": "Int32",
                "shape": [10],
                "data": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}}}

Now for a simple sequence, also with data. We have this DDS:

Dataset {
    Sequence {
        Int32 a;
        Int32 b;
    } seq;
} dataset;

The dataset has the following JSON representation:

Content-description: dods_json
XDODS-Server: dods/2.0
Content-type: application/json

{"dataset": {"type": "Dataset",
             "seq": {"type": "Sequence",
                     "a": {"type": "Int32",
                           "data": [0, 1, 2, 3, 4]},
                     "b": {"type": "Int32",
                           "data": [5, 6, 7, 8, 9]}}}}

The response describes a dataset with a variable seq of type Sequence; this variable has two variables a and b of type Int32 without attributes. Here's another example, this time with nested sequences (again with output_data=1):

Dataset {
    Sequence {
        Int32 lat;
        Int32 lon;
        Sequence {
            Int32 depth;
            Int32 temp;
            Int32 saln;
        } profile;
    } seq;
} dataset;
Content-description: dods_json
XDODS-Server: dods/2.0
Content-type: application/json

{"dataset": {"type": "Dataset",
             "seq": {"type": "Sequence",
                     "lat": {"type": "Int32",
                             "data": [-10, -11]},
                     "lon": {"type": "Int32",
                             "data": [70, 71]},
                     "profile": {"type": "Sequence",
                                 "depth": {"type": "Int32",
                                           "data": [[100, 200], [101, 201]]},
                                 "temp": {"type": "Int32",
                                          "data": [[24, 23], [23, 21]]},
                                 "saln": {"type": "Int32",
                                          "data": [[35, 36], [34, 35]]}}}}}

As you can see, there's a direct mapping between the DDS, the DAS and the JSON response. Here's a final example, covering structures and grids:

Dataset {
    Structure {
        Grid {
            Array:
                Int32 grid[x = 2][y = 3];
            Maps:
                Int32 x[x = 2];
                Int32 y[y = 3];
        } grid;
    } s;
} dataset;
Content-description: dods_json
XDODS-Server: dods/2.0
Content-type: application/json

{"dataset": {"type": "Dataset",
             "s": {"type": "Structure",
                   "grid": {"shape": [2, 3],
                            "dimensions": ["x", "y"],
                            "type": "Grid",
                            "array": {"grid": {"shape": [2, 3],
                                               "dimensions": ["x", "y"],
                                               "type": "Int32",
                                               "data": [[1, 2, 3], [4, 5, 6]]}},
                            "maps": {"x": {"shape": [2],
                                           "type": "Int32",
                                           "data": [1, 2]},
                                     "y": {"shape": [3],
                                           "type": "Int32",
                                           "data": [1, 2, 3]}}}}}}