Transforming

mappyfile parses a Mapfile and turns it into a Abstract Syntax Tree (AST). The mappyfile transformer class then turns this tree into a Python dictionary. Using a dictionary provides the Python developer with a familiar data structure that can be used to edit the Mapfile further - see Editing a Mapfile.

For example taking the Mapfile below:

MAP
    EXTENT -180 -90 180 90
    NAME "MyMap"
    WEB
        METADATA
            "wms_enable_request" "*"
            "wms_feature_info_mime_type" "text/html"
        END
    END
    PROJECTION
        "init=epsg:4326"
    END
    LAYER
        PROCESSING "BANDS=1"
        PROCESSING "CONTOUR_ITEM=elevation"
        PROCESSING "CONTOUR_INTERVAL=20"
        EXTENT -180 -90 180 90
        NAME "rgb"
        TYPE RASTER
        DATA "../data/raster/bluemarble.tif"
        TEMPLATE "raster.template.html"
    END
END

The following code can be used to see the dictionary structure (represented here as a JSON object):

import mappyfile
import json

mf = mappyfile.open("./docs/examples/after.map")

with open("./docs/examples/sample.json", "w") as f:
    json.dump(mf, f, indent=4)

Output:

{
    "__type__": "map",
    "extent": [
        -180,
        -90,
        180,
        90
    ],
    "name": "MyMap",
    "web": {
        "__type__": "web",
        "metadata": {
            "wms_enable_request": "*",
            "wms_feature_info_mime_type": "text/html",
            "__type__": "metadata"
        }
    },
    "projection": [
        "init=epsg:4326"
    ],
    "layers": [
        {
            "__type__": "layer",
            "processing": [
                "BANDS=1",
                "CONTOUR_ITEM=elevation",
                "CONTOUR_INTERVAL=20"
            ],
            "extent": [
                -180,
                -90,
                180,
                90
            ],
            "name": "rgb",
            "type": "RASTER",
            "data": "../data/raster/bluemarble.tif",
            "template": "raster.template.html"
        }
    ]
}

Some notes on the above:

  • Objects that can have multiple instances (for example LAYER and CLASS in a Mapfile will be stored in lists (order is important).

  • Most objects have a set of key/value pairs. PROJECTION however is treated as a list (see http://www.mapserver.org/mapfile/projection.html).

  • Some keys are already quoted e.g. in the METADATA object items such as “wms_enable_request” are strings rather than keywords.

  • Some keys are duplicated within an object. E.g.

    PROCESSING "BANDS=1"
    PROCESSING "CONTOUR_ITEM=elevation"
    PROCESSING "CONTOUR_INTERVAL=20"
    

    These are turned into lists:

    "processing": [
        "'BANDS=1'",
        "'CONTOUR_ITEM=elevation'",
        "'CONTOUR_INTERVAL=20'"
    ],
    

Python dictionaries map closely to JSON data structures, which means the Mapfile dictionary structure can be formalised into a JSONSchema. See Mapfile Schema for more details, and also the draft MapServer proposal MS RFC 123: Mapfile JSON Schema.

Mappyfile Additions

In order to ensure that no information is lost when inputting and outputting a Mapfile, mappyfile makes use of hidden properties to store additional data. This data is not outputted as part of the pretty-print. For example a hidden property is used to store objects of the same type e.g. LAYER, CLASS, and STYLE.