如何使用 Mapscript 处理图层模板以响应 WMS GetFeatureInfo 请求
我正在尝试使用 c# mapscript 处理 GetFeaturInfo WMS 请求。在使用 Mapscript 之前,我们的软件将 WMS 请求传递到托管在 IIS 上的 CGI 地图服务器。这会处理与每个查询层关联的 html 模板,并用模板中的许多标记替换数据。
我们无法使用mapserver cgi 实现,因此我尝试通过C# mapscript 机制使用mapscript 重新实现此机制。
到目前为止我所拥有的代码摘要就在这里。这样做的问题是,对 processQueryTemplate 的调用会导致抛出 AccessViolation Exception。
public string GetFeatureInfoFromWMS(NameValueCollection WMSqueryString)
{
//Set the projection library environment variable used by mapscript.dll
Environment.SetEnvironmentVariable("PROJ_LIB", ProjectionLibraryPath);
string output = string.Empty;
try
{
using (mapObj map = new mapObj(MapFile))
{
//Add aditional layer specific params - ie location of plugins etc
ProcessLayers(map, WMSqueryString);
map.web.metadata.set("wms_onlineresource", WMSOnlineResourceURL);
string xVal = WMSqueryString["X"];
string yVal = WMSqueryString["Y"];
if (xVal == null || yVal == null)
{
throw new ArgumentNullException("The X or Y point value has not been suppplied in the GetFeatureInfo request");
}
double pointX = 0.0;
double pointY = 0.0;
try
{
pointX = Convert.ToDouble(xVal);
pointY = Convert.ToDouble(yVal);
}
catch (Exception e)
{
throw new ArgumentException("The X or Y point value supplied in the GetFeatureInfo request is not a valid decimal",e);
}
string layersQS = WMSqueryString["QUERY_LAYERS"];
if (layersQS == null)
{
throw new ArgumentNullException("The QUERY_LAYERS parameter of the WMS GetFeatureInfo request is not specified correctly");
}
//Load the parameters from the wms request into the map
using (OWSRequest request = new OWSRequest())
{
for (int i = 0; i < WMSqueryString.Count; i++)
{
request.setParameter(WMSqueryString.GetKey(i), WMSqueryString.Get(i));
}
string wmsVersion = WMSqueryString["VERSION"];
if (wmsVersion == null || wmsVersion == string.Empty) wmsVersion = DEFAULT_WMS_VERSION;
map.loadOWSParameters(request, wmsVersion);
}
//Reproject X & Y pixel co-ordinates in map co-ordintes.
double minX = map.extent.minx;
double maxX = map.extent.maxx;
double geoX = minX + ((pointX / (double)map.width) * (maxX - minX));
double minY = map.extent.miny;
double maxY = map.extent.maxy;
double geoY = maxY - ((pointY / (double)map.height) * (maxY - minY));
string[] queryLayers = layersQS.Split(',');
using (pointObj point = new pointObj(geoX, geoY, 0, 0))
{
foreach (string layerName in queryLayers)
{
using (layerObj layer = map.getLayerByName(layerName))
{
int queryResult = layer.queryByPoint(map, point, (int)MS_QUERY_MODE.MS_QUERY_SINGLE, -1);
}
}
}
map.prepareQuery();
string[] names = { "Token1" };
string[] values = { "Value1" };
//BANG!!!!!!
output = map.processQueryTemplate(names, values, 10);
}
return output;
}
catch (Exception ex)
{
throw;
}
}
关联的映射文件如下:
MAP
#
# Start of map file
#
NAME esdm
STATUS ON
TEMPLATEPATTERN "."
SIZE 400 600
UNITS meters
EXTENT 0 0 800000 1200000
IMAGECOLOR 255 255 255
FONTSET fonts.txt
#DEBUG ON
IMAGETYPE PNG
PROJECTION
"init=epsg:27700"
END
OUTPUTFORMAT
NAME "png"
DRIVER "GD/PNG"
IMAGEMODE RGBA
MIMETYPE image/png
EXTENSION png
TRANSPARENT ON
END
# OUTPUTFORMAT
# NAME "imagemap"
# MIMETYPE text/html; driver=imagemap
# DRIVER "imagemap"
# END
#
# Start of web interface definition (including WMS enabling metadata)
#
WEB
METADATA
"wms_title" "SQL mapping data"
"wms_srs" "EPSG:27700 EPSG:4326 EPSG:54004 EPSG:54005 EPSG:900913"
"wms_feature_info_mime_type" "text/plain"
"wms_include_items" "all"
END
END
INCLUDE "mapSymbols.inc"
# BARSActions Point Layer
#-----------------------------------------------------------------------------------------
LAYER
NAME "Actions"
MAXSCALEDENOM 100000000
MINSCALEDENOM 0
METADATA
"wms_title" "BARSActions"
"wfs_title" "BARSActions"
"wms_srs" "EPSG:27700"
END
CONNECTIONTYPE PLUGIN
PLUGIN "SQLPlugin"
DATA "geom from MapLoadTest USING UNIQUE ActionId USING SRID=27700"
FILTER "(OrgUnitId = 1 AND %ActionStatusID% AND %ActionTypeID% AND %AreaIDST(geom)%)"
TYPE POINT
STATUS ON
TOLERANCE 50
TEMPLATE "barsTemplate.htm"
CLASS
COLOR 0 0 255
OUTLINECOLOR 0 0 0
SYMBOL 'star'
SIZE 15
#MAXSIZE 6
#MINSIZE 3
END # end of class object
PROJECTION
"init=epsg:27700"
END
DUMP True
END # end of layer object
# BARSActions Polygon Layer
#-----------------------------------------------------------------------------------------
LAYER
NAME "ActionsPolygons"
MAXSCALEDENOM 100000000
MINSCALEDENOM 0
METADATA
"wms_title" "BARSActionsPolygons"
"wfs_title" "BARSActionsPolygons"
"wms_srs" "EPSG:27700"
END
CONNECTIONTYPE PLUGIN
PLUGIN "SQLPlugin"
DATA "geom from MapLoadTest USING UNIQUE ActionId USING SRID=27700"
FILTER "(OrgUnitId = 2 AND ActionID = 200 AND %ActionStatusID% AND %ActionTypeID% AND %AreaIDST(geom)%)"
TYPE POLYGON
STATUS ON
TOLERANCE 50
TEMPLATE "barsTemplate.htm"
CLASS
COLOR 0 0 255
OUTLINECOLOR 0 0 0
END # end of class object
PROJECTION
"init=epsg:27700"
END
DUMP True
END # end of layer object
END # Map File
映射文件中的各个项目都被标记化(即 sql 插件位置和应用于数据的过滤器)。这是通过调用前面方法中的 ProcessLayers 来处理的。这种机制在绘制地图时似乎不会造成任何问题。对 queryByPoint 的调用有效。它返回成功,并且针对 sql 数据库运行的查询返回预期数据。
我不确定从这里开始哪里以及还需要做什么才能从模板生成输出。我期待对 processQueryTemplate 的调用返回填充的模板。我也不太知道prepareQuery 应该做什么。
干杯
I'm trying to handle GetFeaturInfo WMS requests using c# mapscript. Prior to using mapscript our software passed WMS requests through to a CGI mapserver hosted on IIS. This processed a html template associated with each queried layer and substituted a number of tokens within the template for data.
We cannot use the mapserver cgi implementation so I'm attempting to reimplement this mechanism using mapscript via the C# mapscript mechanism.
The summary of the code I have so far is here. The problem with this is that the call to processQueryTemplate causes an AccessViolation Exception to be thrown.
public string GetFeatureInfoFromWMS(NameValueCollection WMSqueryString)
{
//Set the projection library environment variable used by mapscript.dll
Environment.SetEnvironmentVariable("PROJ_LIB", ProjectionLibraryPath);
string output = string.Empty;
try
{
using (mapObj map = new mapObj(MapFile))
{
//Add aditional layer specific params - ie location of plugins etc
ProcessLayers(map, WMSqueryString);
map.web.metadata.set("wms_onlineresource", WMSOnlineResourceURL);
string xVal = WMSqueryString["X"];
string yVal = WMSqueryString["Y"];
if (xVal == null || yVal == null)
{
throw new ArgumentNullException("The X or Y point value has not been suppplied in the GetFeatureInfo request");
}
double pointX = 0.0;
double pointY = 0.0;
try
{
pointX = Convert.ToDouble(xVal);
pointY = Convert.ToDouble(yVal);
}
catch (Exception e)
{
throw new ArgumentException("The X or Y point value supplied in the GetFeatureInfo request is not a valid decimal",e);
}
string layersQS = WMSqueryString["QUERY_LAYERS"];
if (layersQS == null)
{
throw new ArgumentNullException("The QUERY_LAYERS parameter of the WMS GetFeatureInfo request is not specified correctly");
}
//Load the parameters from the wms request into the map
using (OWSRequest request = new OWSRequest())
{
for (int i = 0; i < WMSqueryString.Count; i++)
{
request.setParameter(WMSqueryString.GetKey(i), WMSqueryString.Get(i));
}
string wmsVersion = WMSqueryString["VERSION"];
if (wmsVersion == null || wmsVersion == string.Empty) wmsVersion = DEFAULT_WMS_VERSION;
map.loadOWSParameters(request, wmsVersion);
}
//Reproject X & Y pixel co-ordinates in map co-ordintes.
double minX = map.extent.minx;
double maxX = map.extent.maxx;
double geoX = minX + ((pointX / (double)map.width) * (maxX - minX));
double minY = map.extent.miny;
double maxY = map.extent.maxy;
double geoY = maxY - ((pointY / (double)map.height) * (maxY - minY));
string[] queryLayers = layersQS.Split(',');
using (pointObj point = new pointObj(geoX, geoY, 0, 0))
{
foreach (string layerName in queryLayers)
{
using (layerObj layer = map.getLayerByName(layerName))
{
int queryResult = layer.queryByPoint(map, point, (int)MS_QUERY_MODE.MS_QUERY_SINGLE, -1);
}
}
}
map.prepareQuery();
string[] names = { "Token1" };
string[] values = { "Value1" };
//BANG!!!!!!
output = map.processQueryTemplate(names, values, 10);
}
return output;
}
catch (Exception ex)
{
throw;
}
}
The associated map file is as follows:
MAP
#
# Start of map file
#
NAME esdm
STATUS ON
TEMPLATEPATTERN "."
SIZE 400 600
UNITS meters
EXTENT 0 0 800000 1200000
IMAGECOLOR 255 255 255
FONTSET fonts.txt
#DEBUG ON
IMAGETYPE PNG
PROJECTION
"init=epsg:27700"
END
OUTPUTFORMAT
NAME "png"
DRIVER "GD/PNG"
IMAGEMODE RGBA
MIMETYPE image/png
EXTENSION png
TRANSPARENT ON
END
# OUTPUTFORMAT
# NAME "imagemap"
# MIMETYPE text/html; driver=imagemap
# DRIVER "imagemap"
# END
#
# Start of web interface definition (including WMS enabling metadata)
#
WEB
METADATA
"wms_title" "SQL mapping data"
"wms_srs" "EPSG:27700 EPSG:4326 EPSG:54004 EPSG:54005 EPSG:900913"
"wms_feature_info_mime_type" "text/plain"
"wms_include_items" "all"
END
END
INCLUDE "mapSymbols.inc"
# BARSActions Point Layer
#-----------------------------------------------------------------------------------------
LAYER
NAME "Actions"
MAXSCALEDENOM 100000000
MINSCALEDENOM 0
METADATA
"wms_title" "BARSActions"
"wfs_title" "BARSActions"
"wms_srs" "EPSG:27700"
END
CONNECTIONTYPE PLUGIN
PLUGIN "SQLPlugin"
DATA "geom from MapLoadTest USING UNIQUE ActionId USING SRID=27700"
FILTER "(OrgUnitId = 1 AND %ActionStatusID% AND %ActionTypeID% AND %AreaIDST(geom)%)"
TYPE POINT
STATUS ON
TOLERANCE 50
TEMPLATE "barsTemplate.htm"
CLASS
COLOR 0 0 255
OUTLINECOLOR 0 0 0
SYMBOL 'star'
SIZE 15
#MAXSIZE 6
#MINSIZE 3
END # end of class object
PROJECTION
"init=epsg:27700"
END
DUMP True
END # end of layer object
# BARSActions Polygon Layer
#-----------------------------------------------------------------------------------------
LAYER
NAME "ActionsPolygons"
MAXSCALEDENOM 100000000
MINSCALEDENOM 0
METADATA
"wms_title" "BARSActionsPolygons"
"wfs_title" "BARSActionsPolygons"
"wms_srs" "EPSG:27700"
END
CONNECTIONTYPE PLUGIN
PLUGIN "SQLPlugin"
DATA "geom from MapLoadTest USING UNIQUE ActionId USING SRID=27700"
FILTER "(OrgUnitId = 2 AND ActionID = 200 AND %ActionStatusID% AND %ActionTypeID% AND %AreaIDST(geom)%)"
TYPE POLYGON
STATUS ON
TOLERANCE 50
TEMPLATE "barsTemplate.htm"
CLASS
COLOR 0 0 255
OUTLINECOLOR 0 0 0
END # end of class object
PROJECTION
"init=epsg:27700"
END
DUMP True
END # end of layer object
END # Map File
Various items in the map file are tokenised (ie the sql plugin location and the filters applied to the data) This is handled by the call to ProcessLayers in the previous method. This mechanism doesn't appear to cause any problems when drawing maps. The call to queryByPoint works. It returns a success and the query run against the sql db returns expected data.
I'm unsure where to proceed from here and what else needs to be done to produce the output from the templates. I was expecting the call to processQueryTemplate to return the populated templetes. I also don't quite know what prepareQuery is supposed to do.
Cheers
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从来不知道如何让模板发挥作用。不过,我设法获取了查询返回的形状的数据库 ID。然后我使用它们在其他地方准备 HTML 结果。
请注意,我使用 map.querybypoint 来处理存在图层组的情况(在这种情况下,图层组名称将作为 wms 请求中的图层名称出现)。
Never figured out how to get the templates to work. However I managed to get the database ID's of the shapes returned by the query. I then use these to prepare the HTML result elsewhere.
Note that I'm using map.querybypoint to deal with situations where there are layer groups (in which case the layergroup name will come across as the layer name in the wms request.