WMS 服务支持一系列操作,例如 GetCapabilities、GetMap、GetStyles 等,这些操作允许客户端应用程序通过将参数附加到服务的 URL 来使用该服务。 GetFeatureInfo 操作以同样的方式工作,它用于以多种格式(如 HTML、XML 和纯文本)返回地图中所查询要素的属性。
以下是 GetFeatureInfo 请求及其默认的 HTML 格式响应的示例:
请求
http://gisserver.domain.com/arcgis/services/ihs_petroleum/MapServer/WMSServer?&service=WMS&version=1.1.0&request=GetFeatureInfo&layers=fields&query_layers=fields&styles=&bbox=47.130647,8.931116,48.604188,29.54223&srs=EPSG:4326&feature_count=10&x=562&y=193&height=445&width=1073&info_format=text/html&
响应
在很多情况下,默认的 HTML、XML 或纯文本响应即满足需求,但也可能会存在想要自定义响应格式或方案以执行特定业务逻辑的情况。 例如,由于互操作的原因,您可能希望以标准模式(如 GML 或 GeoJSON)返回要素信息。
XSLT 模板
可扩展样式表语言转换 (XSLT) 模板是一种根据 WMS GetFeatureInfo 响应生成可读输出的方法。 例如,当向服务器发送 WMS GetFeatureInfo 请求时,服务器将以 XML 格式响应请求的要素。 然后,XSLT 模板将 XML“转换”为指定的格式(如 HTML 或纯文本),从而实现了最后响应的可读性。
查看 WMS GetFeatureInfo XML 响应和 ArcGIS Server 安装随附的默认 XSLT 模板将帮助您更好地了解如何自定义 GetFeatureInfo 响应。 以下部分将做详细介绍。
GetFeatureInfo XML 响应
以下示例是 XML 格式的 WMS 服务中的 GetFeatureInfo 响应:
<?xml version="1.0" encoding="UTF-8"?>
<esri_wms:FeatureInfoResponse version="1.3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:esri_wms="http://www.esri.com/wms" xmlns="http://www.esri.com/wms">
<esri_wms:FeatureInfoCollection layername="fields">
<esri_wms:FeatureInfo>
<esri_wms:Field>
<esri_wms:FieldName><![CDATA[OBJECTID]]></esri_wms:FieldName>
<esri_wms:FieldValue><![CDATA[1]]></esri_wms:FieldValue>
</esri_wms:Field>
<esri_wms:Field>
<esri_wms:FieldName><![CDATA[Shape]]></esri_wms:FieldName>
<esri_wms:FieldValue><![CDATA[Polygon]]></esri_wms:FieldValue>
</esri_wms:Field>
<esri_wms:Field>
<esri_wms:FieldName><![CDATA[Shape_Area]]></esri_wms:FieldName>
<esri_wms:FieldValue><![CDATA[0.009079]]></esri_wms:FieldValue>
</esri_wms:Field>
...
<!-- there could be more <esri_wms:Field> -->
...
<esri_wms:Field>
<esri_wms:FieldGeometry>
<esri_wms:Point><![CDATA[0,0]]></esri_wms:Point>
<esri_wms:Multipoint>
<esri_wms:Point><![CDATA[0,45]]></esri_wms:Point>
<esri_wms:Point><![CDATA[10,55]]></esri_wms:Point>
<!-- there could be more <esri_wms:Point> -->
</esri_wms:Multipoint>
<esri_wms:Polyline>
<esri_wms:Path>
<esri_wms:Point><![CDATA[0,45]]></esri_wms:Point>
<esri_wms:Point><![CDATA[10,55]]></esri_wms:Point>
<!-- there could be more <esri_wms:Point> -->
</esri_wms:Path>
<!-- there could be more <esri_wms:Path> -->
</esri_wms:Polyline>
<esri_wms:Polygon>
<esri_wms:Ring>
<esri_wms:Point><![CDATA[0,45]]></esri_wms:Point>
<esri_wms:Point><![CDATA[10,55]]></esri_wms:Point>
<esri_wms:Point><![CDATA[15,25]]></esri_wms:Point>
<!-- there could be more <esri_wms:Point> -->
</esri_wms:Ring>
<!-- there could be more <esri_wms:Ring> -->
</esri_wms:Polygon>
</esri_wms:FieldGeometry>
</esri_wms:Field>
</esri_wms:FeatureInfo>
...
<!-- there could be more <esri_wms:FeatureInfo> -->
...
</esri_wms:FeatureInfoCollection>
...
<!-- there could be more <esri_wms:FeatureInfoCollection> -->
...
</esri_wms:FeatureInfoResponse>
请注意以下细节:
- 根标签 <FeatureInfoResponse> 可包含多个 <FeatureInfoCollection> 元素。
- 每个 <FeatureInfoCollection> 元素包含单个 WMS 图层中所有标识要素的属性字段和值。
- 单个标识要素的信息包含在 <FeatureInfo> 标签中。 请注意,每个字段的“名称-值”均成对出现。
- 每个 <FeatureInfo> 标签都包含空间参考信息。
- 如果可用,将在 <FieldGeometry> 标签中返回要素几何。
- 字段几何可包含点、多点、折线或面几何。
默认的 XSLT 模板
ArcGIS Server 随附的 XSLT 模板适用于 WMS 功能文件中列出的受支持格式。 例如,如果在 <ArcGIS Server 安装位置>\framework\runtime\ArcGIS\Resources\Styles\WMS 中打开这些模板的目录,将会看到以下内容:
- featureinfo_application_geojson.xsl
- featureinfo_application_vnd.esri.wms_featureinfo_xml.xsl
- featureinfo_application_vnd.ogc.wms_xml.xsl
- featureinfo_text_html.xsl
- featureinfo_text_plain.xsl
- featureinfo_text_xml.xsl
根据它们的文件名可以看出,每个模板用于以便于阅读的格式(如 GeoJSON、纯文本和 XML)生成一个默认的 GetFeatureInfo 响应。
本主题开头带有蓝色标题的示例 HTML 表格是使用默认 XSLT HTML 模板生成的。 或者,如果您希望获取原始 XML 作为响应,则可以将 GetFeatureInfo 请求参数 INFO_FORMAT 设置为 application/vnd.esri.wms_raw_xml。 可以使用此方法来创建自定义 XSLT 模板。
自定义 GetFeatureInfo 响应
现在,我们已对 GetFeatureInfo 响应 XML 和 XSLT 模板有了初步的了解,接下来就可以深入研究两种自定义 WMS GetFeatureInfo 响应的方法。
修改默认的 XSLT 模板
您可以采用的第一种方式是物理修改 XSLT 模板。 例如,如果在文本编辑器中打开 HTML 模板 featureinfo_text_html.xsl,然后将 <Style> 标签替换为以下 XML 代码,则表格标题将显示为红色:
示例 XML
<style type="text/css">
table, th, td {
border:1px solid #e5e5e5;
border-collapse:collapse;
font-family: arial;
font-size: 80%;
color: #333333
}
th, td {
valign: top;
text-align: center;
}
th {
background-color: #ffb7b7
}
caption {
border:1px solid #e5e5e5;
border-collapse:collapse;
font-family: arial;
font-weight: bold;
font-size: 80%;
text-align: left;
color: #333333;
}
</style>
示例响应
但是,如果您决定修改这些模板,则将直接影响通过 ArcGIS Server 发布的任何 WMS。 因此,请避免将任何特定于地图服务的逻辑放到这些模板中。
使用 xsl_template 参数
自定义 GetFeatureInfo 响应的另一种方法是,使用 xsl_template 参数来覆盖默认 XSLT 模板的行为。 xsl_template 是一个特定于 Esri 的参数,可在 XSLT 模板文件的 URL 中设置。 当在 URL 字符串中指定模板时,WMS 将覆盖默认模板并使用已指定的模板。 如果已建立了一个自定义模板,这将是在 GetFeatureInfo 响应中利用模板的最佳方法。
注:
使用 xsl_template 参数时,XSLT 模板不必遵循与默认模板相同的命名约定,但它需要经由 URL 提供。 指定本地路径或 UNC 路径会导致请求失败。
以下是含有 xsl_template 参数的 GetFeatureInfo 请求的示例:
http://gisserver.domain.com/arcgis/services/ihs_petroleum/MapServer/WMSServer?&service=WMS&version=1.1.1&request=GetFeatureInfo&layers=pipelines&query_layers=pipelines&styles=&bbox=47.119661,28.931116,48.593202,29.54223&srs=EPSG:4326&feature_count=10&x=389&y=120&height=445&width=1073&info_format=text/plain&xsl_template=http://server/resources/xsl/featureinfo_application_geojson.xsl
以上 URL 将引用覆盖默认模板的外部模板。 自定义模板 XML 如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:esri_wms="http://www.esri.com/wms" xmlns="http://www.esri.com/wms">
<xsl:output method="text" indent="yes" encoding="ISO-8859-1"/>
<xsl:template match="/">
{
"type": "FeatureCollection",
"spatialReference": { "wkid": <xsl:value-of select="esri_wms:FeatureInfoResponse/esri_wms:FeatureInfoCollection/esri_wms:FeatureInfo/esri_wms:CRS"/> },
"features": [<xsl:for-each select="esri_wms:FeatureInfoResponse/esri_wms:FeatureInfoCollection/esri_wms:FeatureInfo">
{
"type": "Feature",
<xsl:if test="count(esri_wms:Field/esri_wms:FieldGeometry/*) > 0">
"geometry": {
<xsl:for-each select="esri_wms:Field/esri_wms:FieldGeometry">
<xsl:for-each select="esri_wms:Point">"type": "Point", "coordinates": [<xsl:value-of select="."/>]</xsl:for-each>
<xsl:for-each select="esri_wms:Multipoint">"type": "MultiPoint", "coordinates": [<xsl:for-each select="esri_wms:Point">[<xsl:value-of select="."/>]<xsl:if test = "position() != last()">,</xsl:if></xsl:for-each>]</xsl:for-each>
<xsl:for-each select="esri_wms:Polyline">"type": "MultiLineString", "coordinates": [<xsl:for-each select="esri_wms:Path"> [<xsl:for-each select="esri_wms:Point">[<xsl:value-of select="."/>]<xsl:if test = "position() != last()">,</xsl:if></xsl:for-each>]<xsl:if test = "position() != last()">,</xsl:if></xsl:for-each>]</xsl:for-each>
<xsl:for-each select="esri_wms:Polygon">"type": "Polygon", "coordinates": [<xsl:for-each select="esri_wms:Ring"> [<xsl:for-each select="esri_wms:Point">[<xsl:value-of select="."/>]<xsl:if test = "position() != last()">,</xsl:if></xsl:for-each>]<xsl:if test = "position() != last()">,</xsl:if></xsl:for-each>]</xsl:for-each>
</xsl:for-each>
},
</xsl:if>
"properties": {<xsl:for-each select="esri_wms:Field">
"<xsl:value-of select="esri_wms:FieldName"/>": "<xsl:value-of select="esri_wms:FieldValue"/>"<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
},
"layerName": "<xsl:value-of select="../@layername"/>"
}<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
]
}
</xsl:template>
</xsl:stylesheet>
上述模板可以使 WMS 以纯文本 GeoJSON 格式(而不使用默认 HTML 格式)返回其 GetFeatureInfo 响应和要素几何。 GeoJSON 可被多种 JavaScript 库解析,从而以便于阅读的格式将响应集成到网页中。
以下是一个 GetFeatureInfo GeoJSON 响应示例,作为 OpenLayers Web 地图应用程序中 Ext.Grid 的数据源:
基于之前的示例,以下示例模板可用于在响应中嵌入视频对象:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:esri_wms="http://www.esri.com/wms" xmlns="http://www.esri.com/wms">
<!--
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-->
<xsl:output
method="html"
indent="yes"
encoding="UTF-8"
omit-xml-declaration="yes"/>
<xsl:template match="/">
<!--<html>
<head>-->
<style type="text/css">
table, th, td {
border:1px solid #e5e5e5;
border-collapse:collapse;
font-family: arial;
font-size: 80%;
color: #333333
}
th, td {
valign: top;
text-align: center;
}
th {
background-color: #aed7ff;
}
caption {
border:1px solid #e5e5e5;
border-collapse:collapse;
font-family: arial;
font-weight: bold;
font-size: 80%;
text-align: left;
color: #333333;
background-color: #aed7ff;
}
</style>
<!--</head>
<body>-->
<div>
<xsl:for-each select="esri_wms:FeatureInfoResponse/esri_wms:FeatureInfoCollection">
<table width="100%" cellpadding="0" cellspacing="0" border="1">
<tbody>
<caption>layer names: '<xsl:value-of select="@layername"/>'</caption>
<xsl:for-each select="esri_wms:FeatureInfo[1]/esri_wms:Field">
<xsl:variable name="fieldName" select="esri_wms:FieldName"/>
<xsl:variable name="fieldValue" select="esri_wms:FieldValue"/>
<xsl:if test="$fieldName = 'PLOT_SYMBOL_GROUP'">
<xsl:choose>
<xsl:when test="$fieldValue = 2">
<tr>
<td>
wiki link
</td>
<td>
<a target="_blank">
<xsl:attribute name="href">
http://en.wikipedia.org/wiki/Oil_well
</xsl:attribute>
Oil Well
</a>
</td>
</tr>
<tr>
<td>
video
</td>
<td>
<div>
<object width="425" height="344">
<param name="movie" value="http://www.youtube.com/v/HVxsbb1lDsQ"></param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed src="http://www.youtube.com/v/HVxsbb1lDsQ" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed>
</object>
</div>
</td>
</tr>
</xsl:when>
</xsl:choose>
</xsl:if>
</xsl:for-each>
</tbody>
</table>
</xsl:for-each>
</div>
<!--</body>
</html>-->
</xsl:template>
以下是一个 GetFeatureInfo 响应示例,其中 OpenLayers Web 地图应用程序中嵌入了视频:
以下是一个更加完整的示例,该示例大量自定义 GetFeatureInfo 响应以嵌入 JavaScript 代码片段。 该代码将在 Google Earth 插件 web 应用程序中播放游览。 请记住,在此 XSLT 模板中,存在特定于特定 WMS 服务的逻辑。 因此,应始终通过 xsl_template 参数引用此模板。 不应将其设为默认模板。
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:esri_wms="http://www.esri.com/wms" xmlns="http://www.esri.com/wms">
<!--
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-->
<xsl:output
method="html"
indent="yes"
encoding="UTF-8"
omit-xml-declaration="yes"/>
<xsl:template match="/">
<!--<html>
<head>-->
<style type="text/css">
table, th, td {
border:1px solid #e5e5e5;
border-collapse:collapse;
font-family: arial;
font-size: 80%;
color: #333333
}
th, td {
valign: top;
text-align: center;
}
th {
background-color: #aed7ff;
}
caption {
border:1px solid #e5e5e5;
border-collapse:collapse;
font-family: arial;
font-weight: bold;
font-size: 80%;
text-align: left;
color: #333333;
background-color: #aed7ff;
}
</style>
<!--</head>
<body>-->
<div>
<xsl:for-each select="esri_wms:FeatureInfoResponse/esri_wms:FeatureInfoCollection">
<table width="100%" cellpadding="0" cellspacing="0" border="1">
<tbody>
<caption>layer names: '<xsl:value-of select="@layername"/>'</caption>
<xsl:for-each select="esri_wms:FeatureInfo[1]/esri_wms:Field">
<xsl:variable name="fieldName" select="esri_wms:FieldName"/>
<xsl:variable name="fieldValue" select="esri_wms:FieldValue"/>
<xsl:if test="$fieldName = 'WGS84_LONGITUDE'">
<xsl:variable name="lon" select="esri_wms:FieldValue"/>
<tr>
<td>lon</td>
<td><xsl:value-of select="$lon"/></td>
<script type="text/javascript">
popup_lon = '<xsl:value-of select="$lon"/>';
</script>
</tr>
</xsl:if>
<xsl:if test="$fieldName = 'WGS84_LATITUDE'">
<xsl:variable name="lat" select="esri_wms:FieldValue"/>
<tr>
<td>lat</td>
<td><xsl:value-of select="$lat"/></td>
<script type="text/javascript">
popup_lat = '<xsl:value-of select="$lat"/>';
</script>
</tr>
</xsl:if>
<xsl:if test="$fieldName = 'PLOT_SYMBOL_GROUP'">
<xsl:choose>
<xsl:when test="$fieldValue = 14">
<tr>
<td>
3d map
</td>
<td>
<div id="map3d" style="width:384px;height:256px;"></div>
<script type="text/javascript">
google.earth.createInstance(
'map3d',
function(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
var kmlStr = ''
+ '<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">'
+ '<gx:Tour>'
+ '<gx:Playlist><gx:FlyTo>'
+ '<gx:duration>20.0</gx:duration>'
+ '<LookAt>'
+ '<longitude>' + popup_lon + '</longitude>'
+ '<latitude>' + popup_lat + '</latitude>'
+ '<altitude>0</altitude>'
+ '<heading>0</heading>'
+ '<tilt>0</tilt>'
+ '<range>500</range>'
+ '<altitudeMode>relativeToGround</altitudeMode>'
+ '</LookAt>'
+ '</gx:FlyTo></gx:Playlist>'
+ '</gx:Tour>'
+ '</kml>';
var kmlObj = ge.parseKml(kmlStr);
ge.getTourPlayer().setTour(kmlObj);
ge.getTourPlayer().play();
},
function() {
}
);
</script>
</td>
</tr>
</xsl:when>
</xsl:choose>
</xsl:if>
</xsl:for-each>
</tbody>
</table>
</xsl:for-each>
</div>
<!--</body>
</html>-->
</xsl:template>