自定義 WMS GetFeatureInfo 響應

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 GetFeatureInfo 響應

在很多情況下,默認的 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: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> 標籤中。請注意,每個字段的“名稱-值”均成對出現。

默認的 XSLT 模板

ArcGIS Server 附帶的 XSLT 模板用於支持 WMS 的功能文件中列出的格式。例如,如果打開這些模板的目錄(位於 <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

根據它們的文件名可以看出,每個模板用於以便於閱讀的格式(如 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>

示例響應

表格標題爲紅色的 HTML GetFeatureInfo 響應

但是,如果修改這些模板,將對通過 ArcGIS Server 發佈的所有 WMS 造成直接影響。因此,請避免將任何特定於地圖服務的邏輯放到這些模板中。

使用 xslt_template 參數

自定義 GetFeatureInfo 響應的另一種方法是,使用 xslt_template 參數來覆蓋默認 XSLT 模板的行爲。xslt_template 是一個特定於 Esri 的參數,可在 XSLT 模板文件的 URL 中設置。在 URL 字符串中指定該模板時,WMS 將覆蓋默認模板並使用指定的模板。如果已建立了一個自定義模板,這將是在 GetFeatureInfo 響應中利用模板的最佳方法。

注注:

使用 xslt_template 參數時,XSLT 模板不必遵循與默認模板相同的命名約定,但它需要經由 URL 提供。指定本地路徑或 UNC 路徑會導致請求失敗。

以下是含有 xslt_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",
  "features": [<xsl:for-each select="esri_wms:FeatureInfoResponse/esri_wms:FeatureInfoCollection/esri_wms:FeatureInfo">
    {
      "type": "Feature",
      "properties": 
        {<xsl:for-each select="esri_wms:Field">                  
          "<xsl:value-of select="esri_wms:FieldName"/>":"<xsl:value-of select="esri_wms:FieldValue"/>",</xsl:for-each>
        },
      "layerName":"<xsl:value-of select="../@layername"/>"  
    },</xsl:for-each>
  ]
}
  </xsl:template>
</xsl:stylesheet>

上述模板可以使 WMS 以純文本 GeoJSON 格式(而不使用默認 HTML 格式)返回其 GetFeatureInfo 響應。GeoJSON 可被多種 JavaScript 庫解析,從而以便於閱讀的格式將響應集成到網頁中。

以下是一個 GetFeatureInfo GeoJSON 響應示例,作爲 OpenLayers Web 地圖應用程序中 Ext.Grid 的數據源:

作爲 OpenLayers Web 地圖應用程序中 Ext.Grid 數據源的 GetFeatureInfo GeoJSON 響應

基於之前的示例,以下示例模板可用於在響應中嵌入視頻對象:

<?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 地圖應用程序中嵌入了視頻:

OpenLayers Web 地圖應用程序中嵌入了視頻的 GetFeatureInfo 響應

以下是一個更全面的示例,通過嵌入 JavaScript 代碼片段對 GetFeatureInfo 響應做較大範圍的自定義。該代碼會在 Google 地球插件 Web 應用程序中播放內容。請注意,此 XSLT 模板中存在針對特定 WMS 服務的邏輯。因此,應始終通過 xslt_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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章