Validation

A key part of the mappyfile library is to validate Mapfiles - checking that options for various keywords are valid. In order to achieve this a full definition of the Mapfile language has been encoded in a JSON file - see Mapfile Schema.

jsonschema is used to validate a Mapfile by converting the transformed dictionary to JSON. For details on creating JSON schemas see the excellent documentation here.

python-fastjsonschema was also considered, but this does now allow multiple validation errors to be output - only the first error encountered - see this link.

What is Validated?

Each of the Mapfile keywords has a limited set of allowed values. For example a UNIT` setting for a LAYER must be one of the strings in the list below:

{
"units": {
    "enum": [
        "dd",
        "feet",
        "inches",
        "kilometers",
        "meters",
        "miles",
        "nauticalmiles",
        "percentages",
        "pixels"
    ]
}
}

If the Mapfile contains a value not in this list then an error will be raised.

For settings such as COLOR either RGB values or hex codes are allowed. This is accounted for in the schema using the oneOf property:

{
"color": {
    "oneOf": [
        {
            "minItems": 3,
            "items": {
                "minimum": -1,
                "type": "number",
                "maximum": 255
            },
            "type": "array",
            "maxItems": 3
        },
        {
            "pattern": "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$",
            "type": "string",
            "example": "#aa33cc"
        }
    ]
}
}

How to Validate

Mapfile validation can either be run using the Command-line Interface, or directly in Python code:

s = """MAP
    NAME "sample"
    LAYER
        NAME "test"
        STATUS DEFAULT
        DATA "SELECT GEOM
        FROM
        TABLE"
        TYPE LINEX
    END
END"""

d = mappyfile.loads(s, include_position=True)
v = Validator()
errors = v.validate(d, add_comments=True, version=7.6)
for e in errors:
    print(e)

Outputs the following:

{'column': 9, 'message': 'ERROR: Invalid value in TYPE', 'line': 9, 'error': "u'linex' is not one of [u'chart', u'circle', u'line', u'point', u'polygon', u'raster', u'query', u'annotation']"}

The include_position parameter can be set to True when loading a Mapfile (or Mapfile snippet), so that any validation errors include line positions.

The optional version parameter can be used to validate the Mapfile against a specific version of MapServer.