Since web services rely on XML both as a specification language (through WSDL), and as a messaging layer (through SOAP), potentially they can be benefitted from XQuery as an XML processing language. In contrast to usual programming infrastructures like java, XQuery does not have the overhead of the Object/XML mapping.

We have exploited the natural parallelism between XQuery modules and WSDL portTypes as depicted in the figure below. Detailed mappings are discussed in our proposal

For example the following WSDL contract

<definitions
  targetNameSpace="http://www.ethz.ch/"
   xmlns:tns="http://www.ethz.ch/"
  xmlns="http://schemas.xmlsoap.org/wsdl/" >
<message name = "add">
<part name="param1" type="xs:integer"/>
<part name="param2" type="xs:integer"/>
</message>
<message name="addResponse">
<part name="result" type="xs:integer"/>
</message>
<portType name="addPortType">
<operation name="add">
<input message="tns:add"/>
<output message="tns:addResponse"/>
</operatiaon>
</portType>
...
<service name="FirstExample">
<port name="FirstExamplePort" ... >
...
</port>
</service>
</definitions>

is mapped to a XQuery module like:

module namespace ws = "http://www.ethz.ch/";
declare function ws:add($param1 as xs:integer, $param2 as xs:integer) as xs:integer;

Notice that this library module only includes the signature of the functions and the when they are called,  the runtime environment of the XQuery has to bind the call with the remote implementation of it. Hence the it’s  completely transparent from the programmer’s point of view. The Following subsections provide examples using our implementation of this extension in MXQuery.

Importing web service into MXQuery

Using these mechanism, WSDL imports and web service invocations can be handled like module import and functions calls.

Example 1: Calling the Google’s spell-checking service (WSDL) to find the correct spelling of the word ‘relattion’.

import module namespace ws="urn:GoogleSearch" at "http://api.google.com/GoogleSearch.wsdl";
ws:doSpellingSuggestion("oIqddkdQFHIlwHMXPerc1KlNm+FDcPUf","relattion")

Note: The first argument is a string, containing the developer key.

Example 2:

Composing two web services, a spell-checking service [2] and a dictionary service [3],  using XQuery (instead of BPEL!)

import module namespace ggl="urn:GoogleSearch" at "http://api.google.com/GoogleSearch.wsdl";
import module namespace dct="http://services.aonaware.com/webservices/"
   at "http://services.aonaware.com/DictService/DictService.asmx?WSDL";
let $spelledWord := ggl:doSpellingSuggestion("oIqddkdQFHIlwHMXPerc1KlNm+FDcPUf",$input)
return
 if (fn:string-length($spelledWord)=0)
 then (dct:Define(<Define xmlns="http://services.aonaware.com/webservices/">
       <word>{$input}</word></Define>)//dct:WordDefinition)
 else (dct:Define(<Define xmlns="http://services.aonaware.com/webservices/">
          <word>{$spelledWord}</word></Define>)//dct:WordDefinition)

This short XQuery code first checks whether the input word has the correct spelling or not. If yes (result of the spell checking service is empty), returns the definition for the original word, otherwise returns the definition of the corrected word

Low-Level SOAP calls

In order to have a more flexible and powerful interaction with the SOAP based Web Services, MXQuery also provides a low level access to the web service functions from the XQuery programs which allows programmers to have more control over the interactions. It has been done by adding two simple functions to the set of XQuery built-in functions which let us to compose custom request messages. The signatures of these functions are as follows
fn:soap-call($locationURI as xs:anyURI,$xmlcontent as node()?) as document()?
fn:soap-call($locationURI as xs:anyURI, $method as xs:string, $header as xs:string, $xmlcontent as node()?) as document()?
Summary:  A call  to these delivers the SOAP payload inside $xmlcontent to $locationURI and retrieves the results as an XML document.  In the second version, the transport method (e.g. HTTP GET/POST) and additional header values can be provided.

Example: calling the ‘doSpellingSuggestion’ method from the Google’s search service by manually created the soap message:

let $input:=
<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
 <SOAP-ENV:Body>
<tns:doSpellingSuggestion xmlns:tns='urn:GoogleSearch' SOAP-
ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
 <key xsi:type='xsd:string'>oIqddkdQFHIlwHMXPerc1KlNm+FDcPUf</key>
<phrase xsi:type='xsd:string'>relattion</phrase>
</tns:doSpellingSuggestion>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
let $temp:= soap-call(xs:anyURI("http://api.google.com/search/beta2"),"POST","",$input)
 return $temp//return/text()

Exporting SOAP

In order to expose our XQuery programs, we need to use a web server and also a web based version of the MXQuery implementation. In current release of the MXQuery there is “.war” version of the MXQuery which you can deploy it to any java servlet container.

To expose your XQuery library modules as a web service, you need to

1)copy your XQuery file (with extension ‘.xquery’) to the root directory of MXQuery web application on the server.Please notice that there are some are sample modules already copied there.

2) if your library module is using (importing) schema types, you also need to copy those type definitions ( as ‘.xsd’ files) to the root directory of the MXQuery web application.(as in the provided samples)

By doing this, you should be able to view the list of exposed modules (and schemas) at: http://serveraddress:port/MXQuery/

Example: as a complementary for the previous subsection, if you want to expose the result of a web service composition as another web service on its own, you just need to wrap the composition code in an XQuery function/module declaration and then copy it to the MXQuery directory on the server. For example, our complex spell-checking/dictionary operation can be wrapped in following fashion

module namespace cmp ="http://ethz.ch/";
import module namespace ggl="urn:GoogleSearch" at "http://api.google.com/GoogleSearch.wsdl";
import module namespace dct="http://services.aonaware.com/webservices/" at
   "http://services.aonaware.com/DictService/DictService.asmx?WSDL";
declare function cmp:spellAndDict($input as  xs:string) {
 let $spelledWord := ggl:doSpellingSuggestion("oIqddkdQFHIlwHMXPerc1KlNm+FDcPUf",$input)
 return
 if (fn:string-length($spelledWord)=0)
 then (dct:Define(<Define xmlns="http://services.aonaware.com/webservices/">
    <word>{$input}</word></Define>)//dct:WordDefinition)
 else (dct:Define(<Define xmlns="http://services.aonaware.com/webservices/">
    <word>{$spelledWord}</word></Define>)//dct:WordDefinition)
 };

And after copying it to the MXQuery directory on the server, following WSDL will be generated

<definitions name="MXQueryWebService" 
  targetNamespace="http://ethz.ch/" 
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
   xmlns:tns="http://ethz.ch/" 
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
   xmlns="http://schemas.xmlsoap.org/wsdl/" >
 <message name="spellAndDict">
 <part name="p0" type="xs:string"/>
 </message>
 <message name="spellAndDictResponse">
 <part name="return" type="xs:anyType"/>
 </message>
 <portType name="port">
 <operation name="spellAndDict">
 <input name="input1" message="tns:spellAndDict"/>
 <output name="output1" message="tns:spellAndDictResponse"/>
 </operation>
 </portType>
 <binding name="binding" type="tns:port">
...
 </binding>
 <service name="MXQueryWebService">
...
 </service>
</definitions>