17.1.18.Document Literal Encoding

The Virtuoso SOAP server and client support Document Literal encoding for processing as an alternative to SOAP/RPC. The document/literal encoding allows the transmission of any arbitrary valid XML document instead of a SOAP call following rules from section 5 from SOAP/1.1 specification. This allows us to send and receive SOAP packets that are more free-form ("document" style). If you create a service that can accept more free-form type packets, you can employ constraints within the methods so that they can be independent (bare) or serialized as embedded elements within the method's SOAP structure (wrapped parameters style).

Example17.15.Comparing SOAP Types

Here are examples of SOAP requests that represent the RPC, Doc/Literal and Doc/Literal with parameters types of SOAP message

-- RPC encoded --

<?xml version="1.0"?>
<SOAP-ENV:Envelope
      xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Body>
     <m:echoString
         SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
         xmlns:m="http://soapinterop.org/">
           <param0 xsi:type="xsd:string">Enter a message here</param0>
     </m:echoString>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

-- Document Literal --

<?xml version="1.0"?>
<SOAP-ENV:Envelope
      xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Body>
     <ns1:echoStringParam xmlns:ns1="http://soapinterop.org/xsd">Enter a message here</ns1:echoStringParam>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

-- Document Literal with parameters --

<?xml version="1.0"?>
<SOAP-ENV:Envelope
      xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Body>
     <ns1:echoString xmlns:ns1="http://soapinterop.org/xsd">
       <param0>Enter a message here</param0>
     </ns1:echoString>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

SOAP operations can be designated as document/literal or RPC by using the appropriate values in the WSDL description file associated to that SOAP endpoint. As Virtuoso SOAP operations are PL procedures special keywords are used within the procedure to indicate that the document/literal encoding should be used. These special keywords are:

__soap_doc
__soap_docw

These should be placed after the 'returns' keyword in a Virtuoso procedure definition. If 'returns ... __soap_type' is omitted the procedure return type will be equivalent to 'returns varchar __soap_type 'http://www.w3.org/2001/XMLSchema:string'.

Another way to expose a PL procedure or UDT method as a document/literal SOAP methods is to use non-explicit XMLSchema datatypes and to force encoding rules via virtual directory option 'Use' (see also SOAP options section in this chapter and in WSDL chapter section: "Exposing SQL Stored Procedures containing complex datatype definitions" for details and examples).

Example17.16.SOAP Returns RPC

The following example shows a procedure that will be exposed as an RPC encoded SOAP operation:

create procedure
Import1.echoString (in x nvarchar __soap_type 'http://www.w3.org/2001/XMLSchema:string')
returns nvarchar __soap_type 'http://www.w3.org/2001/XMLSchema:string'
{
  return x;
};

Example17.17.SOAP Returns Document Literal

The following example shows a procedure that will be exposed as a document literal encoded operation. Note the __soap_doc keyword after 'returns', also in this case __soap_type for each parameter must be specified since the incoming request must be validated by the given schema element declaration (see below for XMLSchema elements declaration).

create procedure
DocLit.echoString (in echoStringParam varchar __soap_type 'http://soapinterop.org/xsd:echoStringParam')
      returns any __soap_doc 'http://soapinterop.org/xsd:echoStringReturn'
{
      return echoStringParam;
};

Example17.18.SOAP Returns Document Literal with Parameters

The following example shows a procedure that will be exposed as document literal encoding operation with parameters style (wrapped). note the __soap_docw keyword after 'returns'.

create procedure
DocPars.echoString (in echoString varchar __soap_type 'http://soapinterop.org/xsd:echoString')
      returns any __soap_docw 'http://soapinterop.org/xsd:echoStringResponse'
{
      return echoString;
};

In both cases of Document Literal encoding we need to specify the schema element for validation of the incoming SOAP request. Furthermore, this applies to the output elements and return value, as they need to be encoded/validated properly.

Defining WSDL Schema Data Type and Elements

When defining a schema data type (for use within SOAP) the 'targetNamespace' attribute on top level element must be specified in order to describe in which namespace this type is valid. In other words, this type will be used to validate request only within this namespace. Therefore it will be exposed only at this WSDL point where it is used to describe a parameter of an operation associated to it.

[Important] Important

All datatypes and elements defined for use in SOAP must have namespace (QName), which means that 'targetNamespace' must be specified in the definition. All non-qualified types will be rejected in SOAP validation and will not be described in the WSDL file.

Example17.19.Making an array of string data type

Here is an example demonstrating making an array-of-string datatype:

select soap_dt_define('','<complexType name="ArrayOfstring"
   targetNamespace="http://soapinterop.org/xsd"
   xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/"
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
   xmlns="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://soapinterop.org/xsd">
  <complexContent>
     <restriction base="enc:Array">
        <sequence>
           <element name="item" type="string" minOccurs="0" maxOccurs="unbounded" nillable="true"/>
        </sequence>
        <attributeGroup ref="enc:commonAttributes"/>
        <attribute ref="enc:arrayType" wsdl:arrayType="string[]"/>
     </restriction>
  </complexContent>
</complexType>');

As document literal encodings work with elements, the elements must be declared as a part of the WSDL file (in the types/schema section). The declared elements can be used to define a doc/literal encoded SOAP operation. This allows for the definition of an element of request and response to enable the server to understand the requests (validate and process) and respond to them (validate the PL data and serialize properly).

Example17.20.Example of defining elements

Here is an example for the DocLit.echoString SOAP operation using parameters (input parameter and return type):

select soap_dt_define('','<element xmlns="http://www.w3.org/2001/XMLSchema"
                                   name="echoStringParam"
                                   targetNamespace="http://soapinterop.org/xsd" type="string" />');

select soap_dt_define('','<element xmlns="http://www.w3.org/2001/XMLSchema"
                                   name="echoStringReturn"
                                   targetNamespace="http://soapinterop.org/xsd" type="string" />');

Extensions to Simple Types

The attribute extensions to the simple types (string, float, etc...) can be defined and used in SOAP messages. In that case a PL value is represented as a special structure of 3 elements as follows:

vector (<composite>, vector (<attr-name>, <attr-value>, ...), <simple type value>)

Example17.21.An example to define a simple type 'Document'

select soap_dt_define('','<complexType name="Document"
             xmlns="http://www.w3.org/2001/XMLSchema"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             targetNamespace="http://soapinterop.org/xsd">
  <simpleContent>
    <extension base="string">
      <xsd:attribute name ="ID" type="string"/>
    </extension>
  </simpleContent>
</complexType>');

Note that soap_dt_define() does not need the name to be specified when adding a new type, the name/namespace will be extracted from XSD fragment.


WSDL Generation

As the WSDL file generation is based on granted PL procedures exposed to a given SOAP endpoint, only SOAP datatypes and schema elements used for them will be printed in <types> section. If an undeclared datatype is used for an exposed procedure, the error will be printed in an XML comment where the type definition was expected and not found. If an element or datatype refers to other (dependent) types they will also be automatically included. For example, if we have exposed for a SOAP endpoint only the following procedure:

create procedure
INTEROP.echoStructArray (
    in inputStructArray any __soap_type 'http://soapinterop.org/xsd:ArrayOfSOAPStruct')
    __soap_type 'http://soapinterop.org/xsd:ArrayOfSOAPStruct'
{
  return inputStructArray;
};

The schema fragment will consist of both SOAPStructure and ArrayOfSOAPStruct data types declaration:

<schema targetNamespace="http://soapinterop.org/xsd"
   xmlns="http://www.w3.org/2001/XMLSchema"
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" >
     <complexType name="ArrayOfSOAPStruct" >
       <complexContent>
         <restriction base="soapenc:Array">
           <sequence>
             <element name="item" type="ns0:SOAPStruct" minOccurs="0" maxOccurs="unbounded"/>
           </sequence>
           <attribute ref="soapenc:arrayType" wsdl:arrayType="ns0:SOAPStruct[]"/>
           <attributeGroup ref="soapenc:commonAttributes"/>
           <attribute ref="soapenc:offset"/>
         </restriction>
      </complexContent>
    </complexType>
    <!-- Note this fragment, it's included because ArrayOfSOAPStruct depends from it -->

    <complexType name="SOAPStruct" >
       <all>
          <element name="varString" type="string" nillable="true"/>
          <element name="varInt" type="int" nillable="true"/>
          <element name="varFloat" type="float" nillable="true"/>
       </all>
    </complexType>
</schema>

Multiple Namespaces in WSDL and SOAP

When you define a SOAP operation that has parameters from different namespaces or a type referring to a type in another namespace, both will be defined and printed as a separate schema definition in the WSDL file. Hence, we can define a data type in different namespace so they will live together in a single WSDL file. This allows us to make more complex and flexible document-centric style SOAP operations.

Example17.22.Example from the SOAP Interop 3 Tests

This example is of the echoEmployee operation from interop 3 tests:

create procedure
Compound2.echoEmployee (in x any __soap_type 'http://soapinterop.org/employee:x_Employee')
      returns any __soap_doc 'http://soapinterop.org/employee:result_Employee'
{
  return x;
};

This will generate the following schema in the WSDL file (only affected parts are shown):

<definitions
...
xmlns:ns1="http://soapinterop.org/person"
xmlns:ns0="http://soapinterop.org/employee"
... >

<types>
        <schema targetNamespace="http://soapinterop.org/person"
                xmlns="http://www.w3.org/2001/XMLSchema"
                xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" elementFormDefault="qualified" >
           <complexType name="Person" >
              <sequence>
                <element minOccurs="1" maxOccurs="1" name="Name" type="string"/>
                <element minOccurs="1" maxOccurs="1" name="Male" type="boolean"/>
              </sequence>
           </complexType>
        </schema>

        <schema targetNamespace="http://soapinterop.org/employee"
                xmlns="http://www.w3.org/2001/XMLSchema"
                xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" elementFormDefault="qualified" >
                <import namespace='http://soapinterop.org/person' />
            <complexType name="Employee" >
                <sequence>
                   <element minOccurs="1" maxOccurs="1" name="person" type="ns1:Person"/>
                   <element minOccurs="1" maxOccurs="1" name="salary" type="double"/>
                   <element minOccurs="1" maxOccurs="1" name="ID" type="int"/>
                </sequence>
           </complexType>

           <element name="result_Employee" type="ns0:Employee" />
           <element name="x_Employee" type="ns0:Employee" />

        </schema>
</types>
...

The PL procedure is defined to use element declaration x_Employee and result_Employee, so this will automatically include the Employee and Person type, upon which they depend. Also, as these types are defined in different namespace, two schema parts will be specified in the WSDL file.


In practice the SOAP developer needs to define elements and types (using soap_dt_define() function), after this, specifying a parameter of PL procedure (or return type) will cause automatic generation of the associated WSDL description in the manner described. Hence, no user intervention is required besides the initial element/type definition.

SOAP Interop round III Endpoints

The following endpoints are pre-defined in the Demo database for SOAP interop III testing (the WSDL files are in the usual services.wsdl for each group of tests):

  • D tests

    • /r3/EmptySA/ - echoString operation with empty ("") soapAction (PRC encoded)

    • /r3/Import1/ - echoString operation, rpc encoded

    • /r3/Import2/ - echoStruct operation, rpc encoded

    • /r3/Import3/ - echoStruct and adds method echoStructArray, rpc encoded (echoStruct is in different namespace)

    • /r3/Compound1/ - Use of attributes in SOAP payload, including attribute on element of simpleType , doc/literal

    • /r3/Compound2/ - Two schema sections, types in 1st schema references types in the 2nd schema, doc/literal

    • /r3/DocPars/ - Reduced version of SOAPBuilders Interop test wsdl with "parameters" way of describing rpc requests in Document/Literal (Document/Literal - Wrapped). Version has operations echoString, echoArrayOfString and echoStruct

    • /r3/DocLit/ - Reduced version of SOAPBuilders InteropTest test, document/literal mode. Version has operations echoString, echoArrayOfString and echoStruct

    • /r3/RpcEnc/ - Reduced version of SOAPBuilders InteropTest test, rpc/encoded mode. Version has operations echoString, echoArrayOfString and echoStruct

  • E tests

    • /r3/List/ - echo of list structure (as shown) , RPC encoded

      struct list {
        int varInt;
        string varString;
        list child; //nullable
      }
      
      
  • F tests

    • /r3/Hdr/ - Modified version of SOAPBuilders InteropTest test, document/literal mode Version has one operation echoString with 2 headers defined.