WXS服务的MAPScript包装器

作者

弗兰克·沃默丹

联系

Pobox.com上的Warmerdam

介绍

与MapServer的实现 MS RFC 16:MapScript WXS服务 在mapserver 4.9中,mapscript现在能够调用mapserver执行诸如wms、wcs和wfs等ogc Web服务请求的能力,并捕获处理请求的结果。

这使得可以基于原始请求中的信息动态配置映射对象,并捕获处理请求的输出以进行进一步的后处理。

警告

MAPServer CGI控件运行时替换not 在使用mapscript wxs包装器时应用。应用任何映射文件修改取决于您正在编写的mapscript代码。

Python示例

下面这个简单的示例使用的是Python语言,它演示了一个脚本,该脚本在内部提供映射名称,但在其他方面使用正常的MapServer处理。

import mapscript

req = mapscript.OWSRequest()
req.loadParams()

map = mapscript.mapObj( '/u/www/maps/ukpoly/ukpoly.map' )
map.OWSDispatch( req )

OWSRequest对象用于管理已解析的OWS处理选项列表。在上面的示例中,使用loadparams()调用从环境中加载它们,该调用从查询字符串中提取并分析它们,方法与 MAPSERV公司 可执行文件将。

然后我们加载一个映射,并使用该映射上给定的参数调用owsdispatch。默认情况下,发送请求的结果将写入stdout,stdout将返回给客户机。

下面的示例忽略所有传入的参数,并逐个参数手动构造请求参数。它对于测试目的可能比部署WXS服务更有用,但它演示了对请求对象的直接操作。

import mapscript

req = mapscript.OWSRequest()
req.setParameter( 'SERVICE', 'WMS' )
req.setParameter( 'VERSION', '1.1.0' )
req.setParameter( 'REQUEST', 'GetCapabilities' )

map = mapscript.mapObj( '/u/www/maps/ukpoly/ukpoly.map' )
map.OWSDispatch( req )

前一个示例将所有let结果直接返回到客户机。但在某些情况下,我们希望能够捕获请求的结果,并可能以某种自定义方式修改请求的结果。在下面的示例中,我们将讨厌的ogc所需的mime类型(对于错误)强制为simple text/xml(警告-非标准!)

import mapscript

req = mapscript.OWSRequest()
req.loadParams()

map = mapscript.mapObj( '/u/www/maps/ukpoly/ukpoly.map' )

mapscript.msIO_installStdoutToBuffer()
map.OWSDispatch( req )

content_type = mapscript.msIO_stripStdoutBufferContentType()
content = mapscript.msIO_getStdoutBufferBytes()

if content_type == 'vnd.ogc.se_xml':
  content_type = 'text/xml'

print 'Content-type: ' + content_type
print
print content

此示例演示如何捕获将owsrequest的输出捕获到缓冲区,捕获“content type:”头值,并将实际内容捕获为二进制数据。函数的作用是:以字节数组的形式返回stdout缓冲区。如果结果已知为文本,则可以使用msio_GetStdOutBufferString()函数将其作为字符串进行提取,以便于文本操作。

Perl示例

所有基于swig的mapscript语言都可以访问大多数相同的功能。在Perl中,我们可以用脚本创建这样的请求:

#!/usr/bin/perl

use mapscript;

$req = new mapscript::OWSRequest();
$req->setParameter( "SERVICE", "WMS" );
$req->setParameter( "VERSION", "1.1.0" );
$req->setParameter( "REQUEST", "GetCapabilities" );

$map = new mapscript::mapObj( "/u/www/maps/ukpoly/ukpoly.map" );

mapscript::msIO_installStdoutToBuffer();

$dispatch_out = $map->OWSDispatch( $req );

printf "%s\n", mapscript::msIO_getStdoutBufferString();

Perl中的一个问题是,当前没有对二进制缓冲区进行包装,因此无法调用msio_GetStdOutBufferBytes(),因此无法操作二进制结果。

更多Perl示例代码

#!/usr/bin/perl
############################################################################
#
# Name:     wxs.pl
# Project:  MapServer
# Purpose:  MapScript WxS example
#
# Author:   Tom Kralidis
#
##############################################################################
#
# Copyright (c) 2007, Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies of this Software or works derived from this Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
############################################################################/

use CGI::Carp qw(fatalsToBrowser);
use mapscript;
use strict;
use warnings;
use XML::LibXSLT;
use XML::LibXML;

my $dispatch;

# uber-trivial XSLT document, as a file
my $xsltfile = "/tmp/foo.xslt";

# here's the actual document inline for
# testing save and alter $xsltFile above

=comment
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:wfs="http://www.opengis.net/wfs">
 <xsl:output method="xml" indent="yes"/>
 <xsl:template match="/">
  <WFSLayers>
   <xsl:for-each select="//wfs:FeatureType">
    <wfs_layer>
     <name><xsl:value-of select="wfs:Name"/></name>
     <title><xsl:value-of select="wfs:Title"/></title>
    </wfs_layer>
   </xsl:for-each>
  </WFSLayers>
 </xsl:template>
</xsl:stylesheet>
=cut

my $mapfile  = "/tmp/config.map";
# init OWSRequest object
my $req = new mapscript::OWSRequest();

# pick up CGI parameters passed
$req->loadParams();

# init mapfile
my $map = new mapscript::mapObj($mapfile);

# if this is a WFS GetCapabilities request, then intercept
# what is normally returned, process with an XSLT document
# and then return that to the client
if ($req->getValueByName('REQUEST') eq "GetCapabilities" && $req->getValueByName('SERVICE') eq "WFS") {

  # push STDOUT to a buffer and run the incoming request
  my $io = mapscript::msIO_installStdoutToBuffer();
  $dispatch = $map->OWSDispatch($req);

  # at this point, the client's request is sent

  # pull out the HTTP headers
  my $ct = mapscript::msIO_stripStdoutBufferContentType();

  # and then pick up the actual content of the response
  my $content = mapscript::msIO_getStdoutBufferString();

  my $xml  = XML::LibXML->new();
  my $xslt = XML::LibXSLT->new();

  # load XML content
  my $source = $xml->parse_string($content);

  # load XSLT document
  my $style_doc = $xml->parse_file($xsltfile);
  my $stylesheet = $xslt->parse_stylesheet($style_doc);

  # invoke the XSLT transformation
  my $results = $stylesheet->transform($source);
  # print out the result (header + content)
  print "Content-type: $ct\n\n";
  print $stylesheet->output_string($results);
}

# else process as normal
else {
  $dispatch = $map->OWSDispatch($req);
}

Java示例

将输出重定向到缓冲区的一个好处是它是线程安全的。同一进程中的多个线程可以主动处理请求,并将其结果写入不同的输出缓冲区。这个Java例子,用于测试多线程访问,说明了这一点。

import edu.umn.gis.mapscript.mapObj;
import edu.umn.gis.mapscript.OWSRequest;
import edu.umn.gis.mapscript.mapscript;

class WxSTest_thread extends Thread {

  public String       mapName;
  public byte[]       resultBytes;

  public void run() {
      mapObj map = new mapObj(mapName);

      map.setMetaData( "ows_onlineresource", "http://dummy.org/" );

      OWSRequest req = new OWSRequest();

      req.setParameter( "SERVICE", "WMS" );
      req.setParameter( "VERSION", "1.1.0" );
      req.setParameter( "REQUEST", "GetCapabilities" );

      mapscript.msIO_installStdoutToBuffer();

      int owsResult = map.OWSDispatch( req );

      if( owsResult != 0 )
          System.out.println( "OWSDispatch Result (expect 0): " + owsResult );

      resultBytes = mapscript.msIO_getStdoutBufferBytes();
  }
}

public class WxSTest {
  public static void main(String[] args)  {
      try {
          WxSTest_thread tt[] = new WxSTest_thread[100];
          int i;
          int expectedLength=0, success = 0, failure=0;

          for( i = 0; i < tt.length; i++ )
          {
              tt[i] = new WxSTest_thread();
              tt[i].mapName = args[0];
          }

          for( i = 0; i < tt.length; i++ )
              tt[i].start();

          for( i = 0; i < tt.length; i++ )
          {
              tt[i].join();
              if( i == 0 )
              {
                  expectedLength = tt[i].resultBytes.length;
                  System.out.println( "Document Length: " + expectedLength + ", expecting somewhere around 10000 or more." );
              }
              else if( expectedLength != tt[i].resultBytes.length )
              {
                  System.out.println( "Document Length:" + tt[i].resultBytes.length + " Expected:" + expectedLength );
                  failure++;
              }
              else
                  success++;
          }

          System.out.println( "Successes: " + success );
          System.out.println( "Failures: " + failure );

      } catch( Exception e ) {
          e.printStackTrace();
      }
  }
}

PHP示例

在php mapscript中可以访问大多数相同的功能。下面是一个显示 wms capabilities .

Example1 : get the capabilities
This is for example what a url could look like :
http://.../php/ows.php?service=WMS&version=1.1.1&Request=GetCapabilities


<?php

dl("php_mapscript_4.10.0.dll");

$request = ms_newowsrequestobj();

$request->loadparams();

/*exampple on how to modify the parameters :
 forcing the version from 1.1.1 to 1.1.0 */
$request->setParameter("VeRsIoN","1.1.0");

ms_ioinstallstdouttobuffer();

$oMap = ms_newMapobj("../../service/wms.map");

$oMap->owsdispatch($request);

$contenttype = ms_iostripstdoutbuffercontenttype();

$buffer = ms_iogetstdoutbufferstring();

header('Content-type: application/xml');
echo $buffer;

ms_ioresethandlers();

?>


Example2 : get the map
This is for example what a url could look like :

http://.../php/ows.php?SERVICE=WMS&VeRsIoN=1.1.1&Request=GetMap&
LAYERS=WorldGen_Outline


<?php

dl("php_mapscript_4.10.0.dll");

$request = ms_newowsrequestobj();

$request->loadparams();

ms_ioinstallstdouttobuffer();

$oMap = ms_newMapobj("../../service/wms.map");

$oMap->owsdispatch($request);

$contenttype = ms_iostripstdoutbuffercontenttype();

if ($contenttype == 'image/png')
   header('Content-type: image/png');

ms_iogetStdoutBufferBytes();

ms_ioresethandlers();

?>

在非CGI环境中使用(mod_php等)

call establish()将CGI环境变量(query_string和request_方法)解析为owsrequest对象中的参数。在非CGI环境中,例如当PHP、Python和Perl被用作Apache中的“加载模块”或使用Tomcat的Java时,Load PARAMSH()调用将不起作用。事实上,在4.10。x中,它将终止Web服务器实例。

在这些情况下,调用脚本/应用程序需要将请求URL解析为关键字/值对,并通过其他方式分配给owsrequest对象,如上面的一些示例中所示,显式地设置请求参数。

后处理能力

在下面的python示例中,我们处理任何传入的wxs请求,但是如果它是getCapabilities请求,那么我们将用从文件中读取的部分替换功能中的服务部分,该部分是按照我们想要的方式精心定制的。

#!/usr/bin/env python

import sys
import elementtree.ElementTree as ET

import mapscript

req = mapscript.OWSRequest()
req.loadParams()

map = mapscript.mapObj( '/u/www/maps/ukpoly/ukpoly.map' )

#
# Handle anything but a GetCapabilities call normally.
#
if req.getValueByName('REQUEST') <> 'GetCapabilities':

  map.OWSDispatch( req )

#
# Do special processing for GetCapabilities
#
else:
  mapscript.msIO_installStdoutToBuffer()

  map.OWSDispatch( req )

  ct = mapscript.msIO_stripStdoutBufferContentType()
  content = mapscript.msIO_getStdoutBufferString()
  mapscript.msIO_resetHandlers()

  # Parse the capabilities.

  tree = ET.fromstring(content)

  # Strip out ordinary Service section, and replace from custom file.

  tree.remove(tree.find('Service'))
  tree.insert(0,ET.parse('./Service.xml').getroot())

  # Stream out adjusted capabilities.

  print 'Content-type: ' + ct
  print
  print ET.tostring(tree)