XQuery for SOA and Web Services

Buy Now | Download | Learn More

Most SOA architectures are built on XML-based requests and responses (like Web Services and SOAP, for example). XQuery is an ideal language for implementing Web Services, since it can query an incoming request as XML, and query relational databases or XML documents (like configuration files, for example) that have been installed on the middle tier, producing the XML needed for a response.

Querying Web Services
Web services return XML, and XQuery is one of the easiest ways to process the result of a web service. And with DataDirect XQuery, you can issue a web service call inside your query with a simple built-in user defined function. The ddtek:wscall() function can call any web service from within an XQuery. For instance, here is a web service call that gets a stock quote from http://swanandmokashi.com using the function ddtek:wscall(). The first argument gives the location of the web service; the second argument contains the payload of the SOAP request.

ddtek:wscall(
<ddtek:location address="http://www.swanandmokashi.com/HomePage/WebServices/StockQuotes.asmx" 
		soapaction="http://swanandmokashi.com/GetQuotes" />
		,
		<s0:GetQuotes xmlns:s0="http://swanandmokashi.com">
		<s0:QuoteTicker>prgs</s0:QuoteTicker>
		</s0:GetQuotes>
)

As the result of the ddtek:wscall() function is just XML, you can use DataDirect XQuery to handle it along with other XML and relational data sources.

Using XQuery with Web Services
As XQuery can be used to construct XML using any desired structure, it is easy to see how Web Services replying with XML (SOAP, for example) messages to incoming requests can be implemented against XQuery. One simple example of such approach is the servlet example exposing a REST interface.

More complex scenarios can be handled by XQuery, like the one involving the construction of a more complex SOAP response triggered by an incoming SOAP request. Consider for instance Example 1 in the SOAP Primer. The following is an incoming web message.

Example 1. An incoming SOAP request

<?xml version='1.0' ?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"> 
 <env:Header>
 <m:reservation xmlns:m="http://travelcompany.example.org/reservation" 
     env:role="http://www.w3.org/2003/05/soap-envelope/role/next"
      env:mustUnderstand="true">
  <m:reference>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d</m:reference>
  <m:dateAndTime>2001-11-29T13:20:00.000-05:00</m:dateAndTime>
 </m:reservation>
 <n:passenger xmlns:n="http://mycompany.example.com/employees"
     env:role="http://www.w3.org/2003/05/soap-envelope/role/next"
      env:mustUnderstand="true">
  <n:name>Åke Jógvan Øyvind</n:name>
 </n:passenger>
 </env:Header>
 <env:Body>
 <p:itinerary
  xmlns:p="http://travelcompany.example.org/reservation/travel">
  <p:departure>
   <p:departing>New York</p:departing>
   <p:arriving>Los Angeles</p:arriving>
   <p:departureDate>2001-12-14</p:departureDate>
   <p:departureTime>late afternoon</p:departureTime>
   <p:seatPreference>aisle</p:seatPreference>
  </p:departure>
  <p:return>
   <p:departing>Los Angeles</p:departing>
   <p:arriving>New York</p:arriving>
   <p:departureDate>2001-12-20</p:departureDate>
   <p:departureTime>mid-morning</p:departureTime>
   <p:seatPreference/>
  </p:return>
 </p:itinerary>
 <q:lodging
  xmlns:q="http://travelcompany.example.org/reservation/hotels">
  <q:preference>none</q:preference>
 </q:lodging>
 </env:Body>
</env:Envelope>

Let's write the first web service, which returns the airports for an itinerary. First, let's write a function that looks up the airports for a given city in a relational database that is available to the web service implementation.

Example 2. A function to process one airport

declare function local:airportChoices($city as xs:string)
   {
    let $airports := collection("airports")/AIRPORTS[CITY = $city]
    return
     if (count($airports) = 0)
     then 
      <error> No airports found for {$city}!</error>
     else if (count($airports) > 1) 
     then 
      <airportChoices>
      { 
        for $c in $airports/CODE
        return (string-value( $c ), " ")
       }
      </airportChoices>
     else ()
   };

Now let's write a function that looks for all the departing and returning airports in an incoming message. If there is one airport for each city, we return a message containing the airports for the itinerary. If there is more than one airport for a city, or no airport, we return a message which requests clarification.

Example 3. A function to process all airports in a message

declare function local:airports($in as element(env:Envelope))
{
  let $departureDeparting := $in//p:departure/p:departing
  let $departureDepartingAirports := collection("airports")/AIRPORTS[CITY = $departureDeparting]
  let $departureArriving := $in//p:departure/p:arriving
  let $departureArrivingAirports := collection("airports")/AIRPORTS[CITY = $departureArriving]
  let $returnDeparting := $in//p:return/p:departing
  let $returnDepartingAirports := collection("airports")/AIRPORTS[CITY = $returnDeparting]
  let $returnArriving := $in//p:return/p:arriving
  let $returnArrivingAirports := collection("airports")/AIRPORTS[CITY = $returnArriving]
  return
    if ( count($departureDepartingAirports)=0 or count($departureDepartingAirports)>1
     or count($departureArrivingAirports)=0 or count($departureArrivingAirports)>1
     or count($returnDepartingAirports)=0 or count($returnDepartingAirports)>1
     or count($returnArrivingAirports)=0 or count($returnArrivingAirports)>1 )
     then
     <p:itineraryClarification>
      { local:airportChoices($departureDeparting) }
      { local:airportChoices($departureArriving) }
      { local:airportChoices($returnDeparting) }
      { local:airportChoices($returnArriving) }
     </p:itineraryClarification>
     else 
     <p:itinerary>
      <p:departure>
       <p:departing>{$departureDeparting}</p:departing>
       <p:arriving>{$departureArriving}</p:arriving>
      </p:departure>
      <p:return>
       <p:departing>{$returnDeparting}</p:departing>
       <p:arriving>{$returnArriving}</p:arriving>
      </p:return>
     </p:itinerary>
};

In the incoming message, New York City is served by three airports, so the query creates the payload from Example 2 in the SOAP Primer.

<p:itineraryClarification 
  xmlns:p="http://travelcompany.example.org/reservation/travel">
  <p:departure>
   <p:departing>
    <p:airportChoices>
     JFK LGA EWR 
    </p:airportChoices>
   </p:departing>
  </p:departure>
  <p:return>
   <p:arriving>
    <p:airportChoices>
     JFK LGA EWR 
    </p:airportChoices>
   </p:arriving>
  </p:return> 
 </p:itineraryClarification>
Product Information

Quick Links

Querying Web Services

XQuery FAQ