SoapPlugin

SOAP for Foswiki

SoapPlugin is an way to integrate webservices using the SOAP transport protocol. It has got support for service definitions using WSDL as far as supported by SoapLite, the underlying perl library of SOAP operatiosn. For those cases of more complicated WSDL descriptions not covered by SoapLite, endpoints can be be specified manually.

This plugin supports accessing SOAP webservices using basic authentication, that is allows accessing endpoints secured by HTTP credentials.

The xml response of a service endpoint can be parsed and formatted using basic xpath expressions.

Syntax

SOAP

Parameter Description
"..." client to use to access a specific webservice; clients are defined in configure in {SoapPlugin}{Clients}; see the "Configuring Clients" below
id="..." stores the retrieved result under the given ID to be reused in SOAPFORMAT
method="..." remote procedure to be executed on the server side; this is an identifier specific to the service; if not defined defaultMethod is used as specified in the service definition
format="..."
header="..."
footer="..."
separator="..."
these format strings are used to format non-scalar results
xslt="..." instead of using foswiki's format methods you could als use a stylesheet to transform the result
hidenull="on/off" if switched on, the empty response or node won't be displayed, that is even head and footer content is omitted
raw="on/off" if switched on, the xml response is returned as is, that is no formatting is applied
verbatim="on/off" this behaves like raw="on" basically but also pretty-prints the output to ease reading the xml and then puts it into a <verbatim> environment to format it as html
valueof="..." xpath expression to filter the output
depth="int" the depth to which an XML response object should be traversed while rendering it using format, header, footer and separator
warn="on/off" if switched off all error warnings will be suppressed (defaults to on)
cache="on/off" toggles caching on or of (default is off)
expire="seconds/units" indicates the time the soap response is reused from cache if available instead of fetching it from the distant endpoint; expire can either be specified numerically in seconds or using a date expression like "10 minutes". Valid units are s, second, seconds, sec, m, minute, minutes, min, h, hour, hours, d, day, days, w, week, weeks, M, month, months, y, year, and years, as well as now and never

The cache can be invalidated manually by using a refresh=soap (or refresh=on) url parameter.

Any additional parameter like for example EMPLOYEEID in %SOAP{"client-id" method="getVacationOfEmployee" EMPLOYEEID="1606"}% will be passed over to the server and are not interpreted by the SoapPlugin itself. This also means that any required parameter to a webservice method must not overlap with those documented above as part of the %SOAP command.

A parameter may contain nested argument structures which are then translated to nested xml structures. For example

%SOAP{
   ...
   STORNO="
     STARTDATE=\"20101101\"
     ENDDATE=\"20101107\"
   "
}%

Will be translated to a call using

<STORNO>
  <STARTDATE>20101101</STARTDATE>
  <ENDDATE>20101107</ENDDATE>
</STORNO>

When the name of an argument to a SOAP method clashes with a parameter of the %SOAP macro, e.g. format, depth etc, then SOAP arguments can be specified using a param_... prefix to distinguish them:

%SOAP{
  method="..."
  param_format="..."
  param_depth="..."
}%

In some rare cases of a rather crude webservice interface (like the one for the National Weather Service, see below), it is required to order arguments passed to the SOAP method as they aren't recognized correctly otherwise. This can be achieved using a param1_..., param2_... etc prefix:

%SOAP{
  method="..."
  param1_latitude="..." 
  param2_longitude="..." 
  param3_startDate="..." 
  param4_numDays="..." 
  param5_Unit="..."
  param6_format="..."
}%

That way arguments will be sorted accordingly in the SOAP request structure.

SOAPFORMAT

Parameter Description
"..." (or id="...") this refers to a previous %SOAP call that was stored at the given ID using the id parameter to %SOAP
format="..."
header="..."
footer="..."
separator="..."
these format strings are used to format non-scalar results
hidenull="on/off" if switched on, the empty response or node won't be displayed, that is even head and footer content is omitted
raw="on/off" if switched on, the xml response is returned as is, that is no formatting is applied
verbatim="on/off" this behaves like raw="on" basically but also pretty-prints the output to ease reading the xml and then puts it into a <verbatim> environment to format it as html
valueof="..." xpath expression to filter the output
depth="int" the depth to which an XML response object should be traversed while rendering it using format, header, footer and separator

So the parameters to %SOAPFORMAT are mostly the same as those for %SOAP except method. This is not needed as SOAPFORMAT formats the response already received by accessing the server/method of the previous %SOAP call.

If the node selected by the valueof xpath expression is not a scalar value, e.g. addresses a node in the xml response which contains further child nodes, then the result is rendered recursively using format, header, footer and separator while traversing the xml output.

When visiting a node, the following variables can be used to access its properties:

  • $name: (or $key): the name of the node
  • $value: the value of the node; this expands recursively when the value is not a final child node
  • $type: the type of the node according to the WSDL definition
  • $uri: the URI that will be used as the namespace
  • $prefix: the prefix used when associating the node with a specific namespace
  • $attr(...): the value of the named attribute
  • $index: the index of this node in a list of sibling nodes
  • $depth: the distance from the root node of the contained xml document
  • $valueof(...): the value of the node as specified by the enclosed xpath expression; note: in contrast to the valueof parameter of the %SOAP/SOAPFORMAT tag itself, this only returns the first matching value

Standard escapes may be used in all format strings, that is $percnt, $nop, $n and $dollar.

Configuring Clients

Each client specifies an service that Foswiki might talk to using SOAP. These have to be defined upfront using configure. A service is then connected using %SOAP{"service-id" ...}%.

Example:

$Foswiki::cfg{SoapPlugin}{Clients} = [
  {
    id => 'portal',
    uri => 'urn:company.com:xi:ess_r2',
    proxy => 'http://company.com:50000/XISOAPAdapter/MessageServlet?channel=:Portal:Portal_Webservice',
    xmlns => 'urn:sap-com:document:sap:rfc:functions',
    user => 'soap_user',
    password => 'soap_password',
    defautMethod => 'EMPLOYEE_FUNCTION'
  },
  {
    id => 'mockup',
    uri => 'urn:company.com:xi:ess_r2',
    proxy => 'http://127.0.0.1:8088/mockPortalBinding',
    xmlns => 'urn:sap-com:document:sap:rfc:functions',
  }
];

This defines two clients that are stored under the IDs portal and mockup. These are then used by a %SOAP{"portal" method="..."}% or %SOAP{"mockup" method="..."}% statement respectively.

The following list of parameters might be used to configure a service:

Parameter Description
id => "..." symbolic name to make use of the connection
uri => "..."
proxy => "..."
xmlns => "..."
resource specification of the given endpoint definition; please look up the SOAP documentation of that service for more details
wsdl => "..." url of the WSDL definition; either use uri + proxy or wsdl to specifiy a connection
defaultMethod => "..." default method to be used by this client; can be overriden using the method parameter of a %SOAP call
user => "..."
password =>"
user name and password in case the webservice is access protected using HTTP credentials
namespace => [
 "id" => "urn",
 "id" => "urn",
 ...
]
list of namespaces to be defined as part of the protocol; this is a set of extra namespaces that might be used when talking to the SOAP server; most of the time specifying xmlns is enough to defined the default namespace with which methods are called

Foswiki specific SOAP headers

Every message created by SoapPlugin adds a set of foswiki-specific headers which are defined in the foswiki:http//schema.foswiki.org/soap namespace. These are

Header Description
foswiki:wikiName
foswiki:loginName
WikiName of the user currently logged in triggering the SOAP call
foswiki:web
foswiki.topic
web and topic from where the SOAP call was issued
foswiki:isAdmin a boolean flag indicating whether the current user is a wiki admin

Example using the National Weather Service

Use this in your LocalSite.cfg to configure the nws endpoint:

$Foswiki::cfg{SoapPlugin}{Clients} = [
#  {
#    ... other clients ...
#  },
  { 
    'id' => 'nws', 
    'wsdl' => 'http://www.weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl',
    'proxy' => 'http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php',
    'xmlns' => 'http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl',
  }
];

Add a weather report to your own page using:

%INCLUDE{"System.SoapPlugin" 
  section="nws::weather"
  latitude="40.78"
  longitude="-73.88"
}%

That's how it would look like if you enabled the plugin:

mockup

%STARTSECTION{"nws::weather"}%
%SOAP{"nws" 
  id="weather"
  cache="on"
  expire="1 day"
  method="NDFDgenByDay" 
  hidenull="off"
  valueof="//dwmlByDayOut"
  format="$value"
  xslt="$percntINCLUDE{\"%WEB%.%TOPIC%\" section=\"xslt\"}$percnt"
  param1_latitude="%latitude%" 
  param2_longitude="%longitude%" 
  param3_startDate="%SERVERTIME{"$year-$mo-$day"}%" 
  param4_numDays="4" 
  param5_Unit="m"
  param6_format="12 hourly"
}%
%ENDSECTION{"nws::weather"}%
%STARTSECTION{"xslt"}%
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method='html' standalone='no' indent='no'/>
<xsl:template match='/'>
  <table class='forecastTable'>
  <xsl:apply-templates select="/dwml/data" /> 
  </table>
  <xsl:apply-templates select="/dwml/head" /> 
<style>
.forecastTable {
  border:1px solid #ddd;
  margin-bottom:1em;
  width:700px;
}
.forecastTable h3 {
  margin:0 0 0.5em 0;
}
.forecastTable td {
  padding:1em;
  width:25%;
  /*border:1px solid #ddd;*/
  vertical-align:top;
}
.forecastTable img {
  border:1px solid #ddd;
  margin:0 0.5em 0.5em 0;
  width:5em;
}
</style>
</xsl:template>

<xsl:template match="head">
<div class="footer foswikiGrayText foswikiSmallish">
<a>
  <xsl:attribute name="target">_blank</xsl:attribute>
  <xsl:attribute name="href"> 
     <xsl:value-of select="source/credit" />
  </xsl:attribute>
</a>
<xsl:value-of select="product/title" />,
<a>
  <xsl:attribute name="target">_blank</xsl:attribute>
  <xsl:attribute name="href"> 
     <xsl:value-of select="source/disclaimer" />
  </xsl:attribute>
  disclaimer
</a>,
<a>
  <xsl:attribute name="target">_blank</xsl:attribute>
  <xsl:attribute name="href"> 
     <xsl:value-of select="source/feedback" />
  </xsl:attribute>
  feedback
</a>
</div>
</xsl:template>

<xsl:template match="time-layout">
   <xsl:if test="/dwml/data/parameters/*[@time-layout=current()/layout-key]/@type = '12 hour' ">
      <tr> 
      <xsl:for-each select="/dwml/data/time-layout[position()=3]/start-valid-time[position()]">
         <xsl:if test="position()=1">
            <xsl:if test="@period-name='Tonight'">
               <td>
                   
               </td>
            </xsl:if>
         </xsl:if>
         <xsl:if test="substring(.,12,8)='06:00:00'">
         <td>
            <h3><xsl:value-of select="@period-name" /></h3>
            <xsl:call-template name="conditions-icon">
               <xsl:with-param name="position" select="position()"/> 
            </xsl:call-template>
            <xsl:call-template name="weather">
               <xsl:with-param name="position" select="position()"/> 
            </xsl:call-template>
            <xsl:call-template name="temperature">
               <xsl:with-param name="position" select="round(position() div 2)"/> 
            </xsl:call-template>
            <xsl:call-template name="POP">
               <xsl:with-param name="position" select="position()"/> 
            </xsl:call-template>
         </td>
         </xsl:if> 
      </xsl:for-each>
     </tr>

     <tr>
        <xsl:for-each select="/dwml/data/time-layout[position()=3]/start-valid-time[position()]"> 
        <xsl:if test="substring(.,12,8)='18:00:00'">
           <td>
              <h3><xsl:value-of select="@period-name" /></h3>
              <xsl:call-template name="conditions-icon">
                 <xsl:with-param name="position" select="position()"/> 
              </xsl:call-template>
              <xsl:call-template name="weather">
                 <xsl:with-param name="position" select="position()"/> 
              </xsl:call-template>
              <xsl:call-template name="temperature">
                 <xsl:with-param name="position" select="round(position() div 2)"/> 
              </xsl:call-template>
              <xsl:call-template name="POP">
                 <xsl:with-param name="position" select="position()"/> 
              </xsl:call-template>
           </td>
        </xsl:if> 
     </xsl:for-each>
     </tr>
   </xsl:if>
</xsl:template>

<xsl:template name="temperature">
   <xsl:param name="position" /> 
   <div class='temperature'>
     <xsl:value-of select="/dwml/data/parameters/temperature[@type='minimum']/value[position()=$position]/."/>
     -
     <xsl:value-of select="/dwml/data/parameters/temperature[@type='maximum']/value[position()=$position]/."/> °C
   </div>
</xsl:template>

<xsl:template name="POP">
   <xsl:param name="position" /> 
   <xsl:if test="/dwml/data/parameters/probability-of-precipitation/value[position()=$position]/. != ''">
      <div class='pop'>
      <xsl:value-of select="/dwml/data/parameters/probability-of-precipitation/value[position()=$position]/."/>% 
       chance of rain
      </div>
   </xsl:if>
</xsl:template>

<xsl:template name="conditions-icon">
   <xsl:param name="position" /> 
   <xsl:if test="/dwml/data/parameters/conditions-icon/icon-link[position()=$position]/. !=''">
      <img>
         <xsl:attribute name="src">
         <xsl:if test=".!=''">
            <xsl:value-of select="/dwml/data/parameters/conditions-icon/icon-link[position()=$position]/."/>
         </xsl:if>
         </xsl:attribute>
         <xsl:attribute name="align">center</xsl:attribute>
      </img>
   </xsl:if>
</xsl:template>

<xsl:template name="weather">
   <xsl:param name="position" /> 
   <xsl:if test="/dwml/data/parameters/weather/weather-conditions[position()=$position]/@weather-summary !=''">
      <div class='weather'>
        <xsl:value-of select="/dwml/data/parameters/weather/weather-conditions[position()=$position]/@weather-summary"/> 
      </div>
   </xsl:if>
</xsl:template>

<xsl:template match="parameters"><!-- deleted --></xsl:template>
<xsl:template match="location"><!-- deleted --></xsl:template>
<xsl:template match="moreWeatherInformation"><!-- deleted --></xsl:template>
</xsl:stylesheet>
%ENDSECTION{"xslt"}%

Installation Instructions

You do not need to install anything in the browser to use this extension. The following instructions are for the administrator who installs the extension on the server.

Open configure, and open the "Extensions" section. Use "Find More Extensions" to get a list of available extensions. Select "Install".

If you have any problems, or if the extension isn't available in configure, then you can still install manually from the command-line. See http://foswiki.org/Support/ManuallyInstallingExtensions for more help.

Known Problems

  1. On some systems CPAN:SOAP::Lite throws a tainted error. SoapPlugin comes with a patch to SOAP::Transport::HTTP to mitigate the problem.
  2. WSDL support of Soap::Lite is rather limitted.

Plugin Info

Author(s): Foswiki:Main/MichaelDaum
Copyright: © 2011-2014 Michael Daum http://michaeldaumconsulting.com
License: GPL (Gnu General Public License)
Release: 3.21
Version: 3.21
Change History:  
28 May 2014: disable automatic type detection in SOAP::Lite: all values are strings
18 Mar 2014: patching bug in SOAP::Lite; better error handling; fixed use of expire parameter; fixed cpan dependencies
05 Sep 2012: upgrading SOAP::Lite shipped with this plugin; added XSLT to %SOAP to "ease" formatting xml results; added caching of perl stubs generated from wsdl; added example using the National Weather Service SOAP interface
18 May 2011: implemented caching; including a local version of SOAP::Lite with patches applied; removed XML::Parser::Lite from the SOAP::Lite package as it is seriously broken; new dependency on XML::Parser (the real thing) now
14 Jun 2010: added warn parameter to suppress error messages; fixed perl rookie error for default values retrieved from a SOM object
10 May 2010: added support for nested argument structures
19 Mar 2010: rewrite of serializer; implemented $valueof() etc; fixed UTF8 handling
16 Mar 2010: initial release
Dependencies:
NameVersionDescription
Cache::Cache>=1.05Required
Class::Inspector>0Required
libxml2>=2.7.5Required
XML::LibXML>1.89Required
XML::LibXSLT>1.75Required
XML::Parser>=2.34Required
Home page: Foswiki:Extensions/SoapPlugin
Support: Foswiki:Support/SoapPlugin

Topic revision: r8 - 28 May 2014, MichaelDaum
 
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. see CopyrightStatement. Creative Commons License