5. Using mapserverapi¶
in order to use Metwork mapserverapi:
mfextaddon_mapserver must be installed
Metwork MFEXT environment must be activated. Note MFEXT is activated if you are working in another Metwork module, e.g. MFDATA, MFSERV, MFBASE…
5.1. C mapserverapi tutorial¶
In this tutorial, we will learn how to use the Metwork C Mapserver APIs.
In order to use Metwork MapServer C APIs, standard compilation tools must be installed (gcc, make…).
5.1.1. Define your MapServer configuration¶
First, we have to define a mapfile to set where data are located and other MapServer configuration.
In this mapfile, we will use two vector layers : ocean
and land
, stored in a zip file containing shapefiles.
For more convenience for ths tutorial, we use the GDAL Virtual File Systems /vsizip/
. However, Virtual layers have a “cost” and are not as fast to display in MapServer as regular layers.
This tutorial mapfile
looks like this:
MAP
IMAGETYPE png
SIZE 500 300
UNITS DD
EXTENT -180 -90 180 90
WEB
IMAGEPATH "/tmp/"
METADATA
"wms_title" "WMS Demo Server"
"wms_onlineresource" "http://demo.mapserver.org/cgi-bin/mapserv?"
"wms_srs" "EPSG:4326"
"ows_enable_request" "*"
'wfs_onlineresource' 'https://demo.mapserver.org/cgi-bin/mapserv/wfs?'
'ows_enable_request' '*'
'wfs_enable_request' '*'
END
END
PROJECTION
"init=epsg:4326"
END
LAYER
NAME 'land'
TYPE POLYGON
STATUS ON
CONNECTIONTYPE OGR
# A full (absolute) path is required for the CONNECTION parameter, for these virtual layers.
# e.g, /tmp/ne_110m_land.zip
CONNECTION "/vsizip//tmp/ne_110m_land.zip"
PROJECTION
'init=epsg:4326'
END
DATA 'ne_110m_land'
CLASS
NAME "ne_110m_land"
STYLE
COLOR 238 236 223
OUTLINECOLOR 255 255 0
WIDTH 1.5
END
END
END
LAYER
NAME 'ocean'
TYPE POLYGON
CONNECTIONTYPE OGR
# A full (absolute) path is required for the CONNECTION parameter, for these virtual layers,
# e.g, /tmp/ne_110m_ocean.zip
CONNECTION "/vsizip//tmp/ne_110m_ocean.zip"
STATUS ON
PROJECTION
'init=epsg:4326'
END
DATA 'ne_110m_ocean'
CLASS
NAME "ne_110m_ocean"
STYLE
COLOR 198 226 242
END
END
END
END
You may need to change the absolute path of the CONNECTION
argument.
For further, check the mapfile documentation.
5.1.2. Write your C code¶
Let’s now write C code
to invoke MapServer throw the Metwork C mapserverapi:
#include <mapserverapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
int main(void) {
FILE *f = fopen("tuto_mapserver.map", "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
gchar *mapfile_content = malloc(fsize + 1);
fread(mapfile_content, 1, fsize, f);
fclose(f);
mapfile_content[fsize] = 0;
g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, g_log_default_handler, NULL);
// Init mapserver
mapserverapi_init();
g_setenv("REQUEST_METHOD", "GET", TRUE);
// Set a GetFeature WFS query on 'land' layer with geometry intersection.
gchar *query_string_wfs = "version=2.0.0&SERVICE=WFS&REQUEST=GetFeature&typename=land&filter=<Filter><Intersects><PropertyName>wkb_geometry</PropertyName><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:posList>45.8362361184359 0.439239133054321 46.231579556351 2.99579336490519 46.073442181185 5.81590988869945 45.4211255086251 5.67753968542917 46.0207297227963 7.43681798415129 45.6583315713742 7.98370973993382 43.9188204445478 7.48953044253997 43.7804502412775 6.19148615471878 43.1479007406134 6.17830804012161 43.0622429957318 4.95933243988344 43.391695860661 3.62175380827074 43.3851068033624 2.20510648907502 43.9451766737421 1.07178863371845 44.7292744922737 0.538074992533092 45.2300428469662 0.22838929949961 45.8362361184359 0.439239133054321</gml:posList></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></Intersects></Filter>";
void *body;
gchar *content_type = NULL;
gsize body_length;
int i = 0;
gboolean b = mapserverapi_invoke(mapfile_content, query_string_wfs, &body, &content_type, &body_length);
if (b == TRUE) {
// you have the full body (WFS XML response in this example) in body variable (this buffer is managed by the library, don't free it by yourself !)
// you have the body length in body_length variable.
// you have the content_type of the body in content_type variable (you have to free it after use).
// Write the WFS response into a file
FILE *fout = fopen("result_wfs.xml", "w");
fprintf(fout,"%s", body);
fclose(fout);
g_free(content_type);
}
// Set a GetMap WMS query on 'ocean' layer
gchar *query_string_wms = "LAYERS=ocean&TRANSPARENT=true&FORMAT=image%2Fpng&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_xml&SRS=EPSG%3A4326&BBOX=-180.0,-90.0,180.0,90.0&WIDTH=500&HEIGHT=250";
b = mapserverapi_invoke(mapfile_content, query_string_wms, &body, &content_type, &body_length);
if (b == TRUE) {
// you have the full body (PNG image in this example) in body variable (this buffer is managed by the library, don't free it by yourself !)
// you have the body length in body_length variable.
// you have the content_type of the body in content_type variable (you have to free it after use).
// Write the WMS response into a file
FILE *fout = fopen("result_wms.png", "wb");
fwrite(body, body_length, 1, fout);
fclose(fout);
g_free(content_type);
}
// Release mapserver
mapserverapi_destroy();
}
5.1.3. Compile your C code¶
The library use pkg-config tool. So you can use the following command to get the compilation flags:
pkg-config --cflags --libs mapserverapi
If not found, you may have to add PREFIX at the end of ${PKG_CONFIG_PATH} environnement variable.
Invoke gcc
to compile the example, the command looks like this:
gcc -pthread -I/opt/metwork-mfext-master/opt/mapserver/include -I/opt/metwork-mfext-master/include/glib-2.0 -I/opt/metwork-mfext-master/lib/glib-2.0/include -pthread -L/opt/metwork-mfext-master/opt/mapserver/lib -L/opt/metwork-mfext-master/lib -lmapserverapi -lmapserver -lgobject-2.0 -lgthread-2.0 -lglib-2.0 tuto_mapserverapi.c
5.1.4. Run the C example¶
Just enter:
./a.out
and check the generated files contents. You can download them to compare with yours: WFS XML response
WMS PNG Response
5.2. Python mapserverapi tutorial¶
In this tutorial, we will learn how to use the Metwork Python3 Mapserver APIs.
We will build in Python 3 the same example as in the C mapserverapi tutorial.
Define your MapServer configuration in the same way as in the C example.
5.2.1. Write your Python code¶
Let’s now write Python code
to invoke MapServer throw the Metwork Python mapserverapi:
import mapserverapi as mapserver
def get_mapfile_content(mapfile_path):
with open(mapfile_path, 'r') as mapfile:
mapfile_content = mapfile.read()
return mapfile_content
def invoke_mapserver_to_file(mapfile_content, query_string, output_file_path):
# Invoke mapserver and save the output to a file
content_type = mapserver.invoke_to_file(mapfile_content, query_string, output_file_path)
if content_type is None:
print("MapServer returned no content")
def invoke_mapserver(mapfile_content, query_string):
# Invoke mapserver and print the output to stdout
content_value, content_type = mapserver.invoke(mapfile_content, query_string)
if content_value is None or content_value[0] is None:
print("MapServer returned no content")
else:
print("Response:\nContent_type:{}\nContent:\n{}".format(content_type, content_value))
if __name__ == "__main__":
# Read the mapfile content.
# We assume tuto_mapserver.map is in the same directory as that the code
mapfile_content = get_mapfile_content("tuto_mapserver.map")
# Set a GetFeature WFS query on 'land' layer with geometry intersection.
query_string_wfs = "version=2.0.0&SERVICE=WFS&REQUEST=GetFeature&typename=land&filter=<Filter><Intersects><PropertyName>wkb_geometry</PropertyName><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:posList>45.8362361184359 0.439239133054321 46.231579556351 2.99579336490519 46.073442181185 5.81590988869945 45.4211255086251 5.67753968542917 46.0207297227963 7.43681798415129 45.6583315713742 7.98370973993382 43.9188204445478 7.48953044253997 43.7804502412775 6.19148615471878 43.1479007406134 6.17830804012161 43.0622429957318 4.95933243988344 43.391695860661 3.62175380827074 43.3851068033624 2.20510648907502 43.9451766737421 1.07178863371845 44.7292744922737 0.538074992533092 45.2300428469662 0.22838929949961 45.8362361184359 0.439239133054321</gml:posList></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></Intersects></Filter>";
# Invoke mapserver and print the output to stdout
invoke_mapserver(mapfile_content, query_string_wfs)
# Set a GetMap WMS query on 'ocean' layer
query_string_wms = "LAYERS=ocean&TRANSPARENT=true&FORMAT=image%2Fpng&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_xml&SRS=EPSG%3A4326&BBOX=-180.0,-90.0,180.0,90.0&WIDTH=500&HEIGHT=250";
# Invoke mapserver and print the output to stdout
invoke_mapserver(mapfile_content, query_string_wms)
# Set a GetFeature WFS query on 'land' layer with geometry intersection.
query_string_wfs = "version=2.0.0&SERVICE=WFS&REQUEST=GetFeature&typename=land&filter=<Filter><Intersects><PropertyName>wkb_geometry</PropertyName><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:posList>45.8362361184359 0.439239133054321 46.231579556351 2.99579336490519 46.073442181185 5.81590988869945 45.4211255086251 5.67753968542917 46.0207297227963 7.43681798415129 45.6583315713742 7.98370973993382 43.9188204445478 7.48953044253997 43.7804502412775 6.19148615471878 43.1479007406134 6.17830804012161 43.0622429957318 4.95933243988344 43.391695860661 3.62175380827074 43.3851068033624 2.20510648907502 43.9451766737421 1.07178863371845 44.7292744922737 0.538074992533092 45.2300428469662 0.22838929949961 45.8362361184359 0.439239133054321</gml:posList></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></Intersects></Filter>";
# Invoke mapserver and save the output to a file
invoke_mapserver_to_file(mapfile_content, query_string_wfs, "result_wfs.xml")
# Set a GetMap WMS query on 'ocean' layer
query_string_wms = "LAYERS=ocean&TRANSPARENT=true&FORMAT=image%2Fpng&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_xml&SRS=EPSG%3A4326&BBOX=-180.0,-90.0,180.0,90.0&WIDTH=500&HEIGHT=250";
# Invoke mapserver and save the output to a file
invoke_mapserver_to_file(mapfile_content, query_string_wms, "result_wms.png")
5.2.2. Run the Python example¶
In order to run the example, you may have choice between running it in a Metwork plugin or as a single python script.
If you run it in a Metwork plugin, you have to add the mapserverapi Python3 layer in the
.layer_dependencies
file of your plugin (in order to load thepython3_mapserverapi@mfext
layer):python3_mapserverapi@mfext
If you run it as a single python script, you have to load the MFEXT environment and run the
Python script
through the layer_wrapper utility in order to load the mapserverapi Python3 layer. Theshell commands
look like that:#!/bin/bash # Activate MFEXT environment MFEXT_HOME=/opt/metwork-mfext export MFEXT_HOME source ${MFEXT_HOME}/share/interactive_profile # Load the python3_mapserverapi@mfext layer and run the mapserverapi.py script layer_wrapper --layers=python3_mapserverapi@mfext -- python tuto_mapserverapi.py
Then, check the generated content and files. You can download them to compare with yours: WFS XML response
WMS PNG Response
6. Using MapServer command-line¶
You can also invoke MapServer through the command-line mapserv.
In order to use mapserv:
mfextaddon_mapserver must be installed
Metwork MFEXT environment must be activated. Note MFEXT is activated if you are working in another Metwork module, e.g. MFDATA, MFSERV, MFBASE…
The you can invoke the command, e.g. :
mapserv -nh "QUERY_STRING=LAYERS=ocean&TRANSPARENT=true&FORMAT=image%2Fpng&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_xml&SRS=EPSG%3A4326&BBOX=-180.0,-90.0,180.0,90.0&WIDTH=500&HEIGHT=250&map=/tmp/tuto_mapserver.map" >/tmp/test_mapserv.png
Notice the map
parameter of the above command refers to the path of the tutorial mapfile
See also
For more details on the mapserv command_line, check mapserv documentation