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 и шаблонов XSLT по умолчанию, поставляемых с установкой ArcGIS Server, поможет вам лучше понять, как настроить ответ GetFeatureInfo. В следующих разделах каждый из них описывается более подробно.
Ответ GetFeatureInfo в формате XML
Ниже представлен пример XML из ответа GetFeatureInfo в WMS-сервисе:
<?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 (capabilities file). Например, если открыть директорию с этими шаблонами в <Папка установки ArcGIS Server>/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
Как следует из их имен, каждый шаблон используется для создания ответа GetFeatureInfo по умолчанию в читаемом формате, таком как GeoJSON, обычный текст и XML.
Пример таблицы HTML с синим заголовком в начале этого раздела был создан с помощью шаблона XSLT HTML по умолчанию. Или же, если вы хотите получить XML в исходном формате в качестве ответа, можно задать для параметра INFO_FORMAT запроса GetFeatureInfo значение application/vnd.esri.wms_raw_xml. Вы можете использовать этот метод для создания собственного шаблона XSLT.
Настройка ответа WMS 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>
Примеры ответов
Но если вы решили изменить эти шаблоны, это напрямую повлияет на любой WMS-сервис, опубликованный на ArcGIS Server. Поэтому постарайтесь избегать добавления логики, касающейся картографических сервисов, в шаблоны.
Использование параметра xsl_template
Другим методом настройки ответа GetFeatureInfo является изменение поведения шаблонов XSLT по умолчанию с помощью xsl_template. xsl_template это параметр Esri, который можно задать в URL-адресе файла шаблона XSLT. Если шаблон указан в строке URL-адреса, WMS заменит шаблон по умолчанию и будет использовать указанный шаблон. Если вы уже создали свой шаблон, то лучше всего его использовать в ответе GetFeatureInfo.
Примечание:
При использовании параметра xsl_template XSLT вы не обязаны следовать правилам именовании шаблонов, которым подчиняются шаблоны по умолчанию, но данный шаблон должен быть доступен по URL-адресу. Если указать локальный путь или сетевой ресурс, запрос завершится с ошибкой.
Ниже представлен пример запроса GetFeatureInfo с параметром xsl_template:
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-сервис возвращал свои ответы GetFeatureInfo в виде обычного текста, GeoJSON вместо стандартного формата HTML. Формат GeoJSON может быть обработан многими библиотеками JavaScript, что позволяет интегрировать ваши ответы в веб-страницы в удобном для чтения формате.
Ниже представлен пример ответа GetFeatureInfo в формате GeoJSON как источника данных Ext.Grid в картографическом веб-приложении OpenLayers:
Следующий пример шаблона можно использовать для внедрения видеообъекта в ответ:
<?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:
Далее представлен более сложный пример, в котором ответ GetFeatureInfo сильно изменен для внедрения фрагмента кода JavaScript. Код проводит тур по веб-приложению Google Earth. Помните, что в этом шаблоне 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>