Pretty Printing

mappyfile can be used to “pretty print” or format Mapfiles. This can be used to standardise a Mapfile with inconsistent formatting. For example:

map
/**
Some comments
*/
            EXTENT -180 -90 180 90    
    NAME "MyMap"
    WEB
metadata
'wms_enable_request'  '*'
'wms_feature_info_mime_type' 'text/html' # this is required to return the content-type for GetFeatureInfo requests       
END
    END

PROJECTION
"init=epsg:4326"
END
 # START OF THE LAYER DEFINITION
    LAYER
    PROCESSING 'BANDS=1'
        PROCESSING 'CONTOUR_ITEM=elevation'
    PROCESSING 'CONTOUR_INTERVAL=20'
     EXTENT -180 -90 180 90 # set this here as it is not stored in the image
     NAME "rgb"
        TYPE RASTER
     DATA '../data/raster/bluemarble.tif' 
     TEMPLATE 'raster.template.html'    
    END    
END

Can be converted using mappyfile to a nicely formatted version using the code below:

import mappyfile

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

The result:

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

Formatting of Mapfiles can be applied using the high-level mappyfile API - see Mapfile Reader and Writer Functions, or using the command-line format.

Please try the online interactive demo at https://app.mapserverstudio.net/ to experiment with the various formatting options in mappyfile. Documentation for MapServer Studio formatting can be found here.

Options

The formatting of the Mapfile output can be configured with several options:

  • spacer - the character to use for indenting structures in the Mapfile. Typically spaces or tab characters (\\t)

  • indent - can be used to set the number of spacer characters to indent structures in the Mapfile

  • quote - the quote character to use in the Mapfile (double or single quotes)

  • newlinechar - the character used to insert newlines in the Mapfile

  • end_comment - add a comment with the block type at each closing END statement e.g. END # MAP

  • align_values - aligns the values in the same column for better readability. The column is multiple of indent and determined by the longest key

  • separate_complex_types - groups composites (complex mapserver definitions with “END”) together at the end. Keeps the given order except that all simple key-value pairs appear before composites.

Warning

When standardising quotes be careful that no quotes chosen for formatting are found within string values. For example large DATA blocks of SQL may contain single quotes which would then create an invalid Mapfile.

Examples

The following example loads a Mapfile from a string, and then dumps it back out as a string. A single tab is used for indenting blocks of the Mapfile:

s = '''MAP NAME "TEST" END'''
d = mappyfile.loads(s)
output = mappyfile.dumps(d, indent=1, spacer="\t")
print(output)

This example adds the block type to its closing END tag:

s = '''MAP NAME "TEST" LAYER NAME "Layer1" END END'''
d = mappyfile.loads(s)
output = mappyfile.dumps(d, end_comment=True)
print(output)

Output:

MAP
    NAME "TEST"
    LAYER
        NAME "Layer1"
    END # LAYER
END # MAP

This example surrounds all attributes with single quotes, and writes the Mapfile directly to disk:

import tempfile
s = '''MAP NAME "TEST" LAYER NAME "Layer1" END END'''
d = mappyfile.loads(s)
output_file = os.path.join(tempfile.mkdtemp(), 'test_mapfile.map')
mappyfile.save(d, output_file)

This example left-aligns all the key values of an object:

s = '''MAP NAME "MyMap"
    OUTPUTFORMAT
    NAME "png"
    DRIVER AGG/PNG
    MIMETYPE "image/png"
    IMAGEMODE RGB
    EXTENSION "png"
    FORMATOPTION "GAMMA=0.75"
    END
    END'''
d = mappyfile.loads(s)
output = mappyfile.dumps(d, align_values=True)
print(output)

Output:

MAP
    NAME    "MyMap"
    OUTPUTFORMAT
        NAME            "png"
        DRIVER          "AGG/PNG"
        MIMETYPE        "image/png"
        IMAGEMODE       RGB
        EXTENSION       "png"
        FORMATOPTION    "GAMMA=0.75"
    END
END

This example moves all the simple key/value pairs of an object to the start of a declaration, and the complex types to the end:

s = '''MAP
WEB
    METADATA
        "wms_enable_request"            "*"
        "wms_feature_info_mime_type"    "text/html"
    END
END
EXTENT  -180 -90 180 90
OUTPUTFORMAT
    NAME            "png"
    DRIVER          "AGG/PNG"
    MIMETYPE        "image/png"
    IMAGEMODE       RGB
    EXTENSION       "png"
END
NAME    "MyMap"
END'''
d = mappyfile.loads(s)
output = mappyfile.dumps(d, separate_complex_types=True)
print(output)

Output:

MAP
    EXTENT -180 -90 180 90
    NAME "MyMap"
    WEB
        METADATA
            "wms_enable_request" "*"
            "wms_feature_info_mime_type" "text/html"
        END
    END
    OUTPUTFORMAT
        NAME "png"
        DRIVER "AGG/PNG"
        MIMETYPE "image/png"
        IMAGEMODE RGB
        EXTENSION "png"
    END
END

This example writes a Mapfile to an open file object using the dump function:

s = """MAP NAME "TEST" END"""
d = mappyfile.loads(s)
with tempfile.NamedTemporaryFile(mode="w+", delete=False) as fp:
    mappyfile.dump(d, fp)