Skip To Content

Настройка ответа WMS GetFeatureInfo

Сервисы WMS поддерживают ряд операций, таких как GetCapabilities, GetMap, Get Styles и т.д., которые позволяют клиентским приложениям работать с сервисом, добавляя параметры к его 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&

Ответ

Ответ GetFeatureInfo в HTML по умолчанию

Во многих случаях подходит стандартный HTML, XML или обычный текстовый ответ, но может возникнуть ситуация, когда вы захотите настроить формат ответа или схему для выполнения определенной бизнес-логики. Например, по соображениям совместимости вам может потребоваться вернуть информацию об объекте в стандартную схему, такую как GML или GeoJSON.

Шаблоны XSLT

Шаблоны Extensible Stylesheet Language Transformation (XSLT) - это способ создания удобочитаемых выходных данных из ответа WMS GetFeatureInfo. Например, когда вы отправляете запрос WMS GetFeatureInfo на сервер, сервер отвечает запрошенными объектами в формате XML. Затем шаблон XSLT выполняет работу по "переводу" XML в указанный формат, такой как HTML или обычный текст, что делает окончательный ответ читабельным.

Ознакомление с XML-ответом WMS GetFeatureInfo и шаблонами 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. Например, если вы откроете директорию этих шаблонов по адресу <ArcGIS Server installation location>\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

Как следует из их названий, каждый шаблон используется для получения ответа GetFeatureInfo по умолчанию в удобочитаемом формате, таком как GeoJSON, обычный текст и XML.

Пример HTML-таблицы с синей подписью, приведенный в начале этого раздела, был создан с использованием шаблона XSLT HTML по умолчанию. Или, если вы хотите получить необработанный XML-файл в качестве ответа, вы можете задать в запросе GetFeatureInfo для параметра INFO_FORMAT значение application/vnd.esri.wms_raw_xml. Вы могли бы использовать этот метод для создания своего собственного шаблона XSLT.

Настройка ответа GetFeatureInfo

Теперь, когда вы лучше понимаете XML- и XSLT-шаблоны ответов GetFeatureInfo, вы можете изучить несколько способов настройки ответа 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>

Пример ответа

Ответ GetFeatureInfo в HTML с красным заголовком

Однако, если вы решите изменить эти шаблоны, это напрямую повлияет на любые WMS, опубликованные через ArcGIS Server. По этой причине избегайте попыток внедрить в шаблоны какую-либо логику, специфичную для картографического сервиса.

Использование параметра xsl_template

Другой способ настройки ответа GetFeatureInfo заключается в переопределении поведения шаблонов XSLT по умолчанию с помощью параметра xsl_template. xsl_template - это параметр Esri, который вы можете задать в URL-адресе файла шаблона XSLT. Если шаблон указан в строке URL, WMS переопределит шаблон по умолчанию и будет использовать указанный вами шаблон. Если вы уже создали пользовательский шаблон, это наиболее подходящий метод для применения шаблона в ответе GetFeatureInfo.

Примечание:

При использовании параметра xsl_template, шаблон XSLT не обязательно должен соответствовать тому же соглашению об именовании, что и шаблоны по умолчанию, но он должен быть доступен по URL-адресу. Указание локального пути или пути UNC приведет к сбою запроса.

Ниже приведен пример запроса 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:

Ответ 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 со встроенным видео в веб-приложении карты 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>