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(Extensible Stylesheet Language Transformation)テンプレートを使用すると、WMS GetFeatureInfo レスポンスから判読可能な出力を生成できます。たとえば、サーバに WMS GetFeatureInfo リクエストを送信すると、サーバはリクエストされたフィーチャを XML 形式で返します。XSLT テンプレートは、XML を HTML やテキストなどの指定された形式に変換し、最終的なレスポンスを判読できるようにします。

WMS GetFeatureInfo XML レスポンスと ArcGIS Server のインストール時に提供されるデフォルトの XSLT テンプレートを検証すると、GetFeatureInfo レスポンスのカスタマイズ方法を理解する際に役立ちます。以下のセクションでは、それぞれについて詳しく説明します。

GetFeatureInfo XML レスポンス

WMS サービスにおける GetFeatureInfo レスポンスの XML の例を示します。

<?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> エレメントには、1 つの WMS レイヤで識別されたすべてのフィーチャの属性フィールドと値が含まれます。
  • 識別された 1 つのフィーチャの情報は、1 つの <FeatureInfo> タグ内に格納されます。フィールドごとに名前と値のペアが存在します。

デフォルトの XSLT テンプレート

ArcGIS Server には、WMS のケーパビリティ ファイルの一覧に表示されるサポートされる形式用に XSLT テンプレートが用意されています。たとえば、これらのテンプレートが格納されているディレクトリ(<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 が必要な場合は、GetFeatureInfo リクエスト パラメータの INFO_FORMAT を application/vnd.esri.wms_raw_xml に設定します。独自の XSLT テンプレートを作成する場合は、この方法を使用します。

GetFeatureInfo レスポンスのカスタマイズ

ここまでは GetFeatureInfo レスポンスの XML および XSLT テンプレートについて説明しました。続いて、WMS GetFeatureInfo レスポンスをカスタマイズする方法について説明します。

デフォルトの XSLT テンプレートの変更

GetFeatureInfo レスポンスをカスタマイズするための 1 つ目の方法は、XSLT テンプレートを物理的に変更することです。たとえば、featureinfo_text_html.xsl HTML テンプレートをテキスト エディタで開き、<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 は、XSLT テンプレート ファイルの URL 内に設定できる Esri 独自のパラメータです。テンプレートが URL 文字列で指定されている場合、WMS はデフォルトのテンプレートの代わりに指定されたテンプレートを使用します。すでに構築済みのカスタム テンプレートを GetFeatureInfo レスポンスで利用する場合は、この方法が最も適切です。

注意注意:

xslt_template パラメータを使用する場合、XSLT テンプレートはデフォルトのテンプレートと同じ命名規則に従っている必要はありませんが、URL を通してアクセスできる必要があります。ローカル パスまたは ネットワーク共有を指定すると、リクエストは失敗します。

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 が GetFeatureInfo レスポンスをデフォルトの HTML 形式ではなく、テキストの GeoJSON 形式で返すように作成されています。GeoJSON は多くの JavaScript ライブラリで解析可能です。これを利用して、レスポンスを Web ページに読みやすい形式で統合できます。

次に示すのは、OpenLayers Web マップ アプリケーションで GetFeatureInfo GeoJSON レスポンスを 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>

OpenLayers Web マップ アプリケーションのビデオが埋め込まれた GetFeatureInfo レスポンスの例を示します。

OpenLayers Web マップ アプリケーションのビデオが埋め込まれた GetFeatureInfo レスポンス

GetFeatureInfo レスポンスをさらにカスタマイズして、JavaScript コード スニペットを埋め込んだ少し複雑な例を示します。コードは、Google Earth プラグイン 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>

6/13/2014