The dynamic-codegen Commons project consists of a set of XSLT stylesheets which can generate stubs from WSDL for dynamic languages. The use of XSLT avoids the necessity for a blown wsdl and schema processors.
Architecture
The basic architecture is a pipeline of XSLT transformations, generalized as follows:WSDL -> signature metafile -> includable stub/tryit
The signature metafile collects the information needed to generate a stub in a simple XML format, and provides a neutral format that could be generated from a full wsdl or schema processor, or from various flavors of WSDL. In essence it is a distilled essence of WSDL plus XML Schema. A pseudo-syntax for the (quickly evolving) format follows:
<?xml version="1.0"?>
<services>
<service name="xs:NCName" -- service name
endpoint="xs:NCName" -- endpoint name
address="xs:anyURI" -- endpoint address
type="xs:string" -- SOAP11 | SOAP12 | HTTP | Unknown binding type: {foo}
>
<documentation/>?
<operations>
<operation name="xs:NCName" pattern="xs:anyURI" safe="xs:boolean">
<documentation/>?
<signature method="rpc-signature | inference">
<params wrapper-element="xs:NCName"
wrapper-element-ns="xs:anyURI">
<param name="xs:NCName" -- parameter name if specified in signature metadata
token="xs:string" -- kind of parameter this is: #in | #out | #inout
type="xs:QName" -- type of the parameter
type-namespace="xs:anyURI" -- namespace of the parameter type
simple="xs:string" -- "yes" if the type is simple, "no" if it's complex
targetNamespace="xs:anyURI" -- targetNamespace of the schema defining the parameter element
maxOccurs="xs:string" -- copy of the xsd maxOccurs for the parameter element
minOccurs="xs:string" -- copy of the xsd minOccurs for the parameter element
nillable="xs:boolean" -- copy of the xsd nillable for the parameter element
>
<param ... /> *
</param> *
</params>
<returns wrapper-element="echoOMElementResponse"
wrapper-element-ns="http://echo.services.wsas.wso2.org/xsd">
<param name="xs:NCName" -- parameter name if specified in signature metadata
token="xs:string" -- kind of parameter this is: #return
type="xs:QName" -- type of the parameter
type-namespace="xs:anyURI" -- namespace of the parameter type
simple="xs:string" -- "yes" if the type is simple, "no" if it's complex
targetNamespace="xs:anyURI" -- targetNamespace of the schema defining the parameter element
maxOccurs="xs:string" -- copy of the xsd maxOccurs for the parameter element
minOccurs="xs:string" -- copy of the xsd minOccurs for the parameter element
nillable="xs:boolean" -- copy of the xsd nillable for the parameter element
> *
<param ... /> *
</param> *
</returns>
</signature>
<binding-details wsawaction="xs:anyURI" -- WS-Addressing explicit action value (SOAP11 | SOAP12)
soapaction="xs:anyURI" -- explicitly declared soap action value (SOAP11 | SOAP12)
method="xs:string" -- {http method} property (SOAP11 | SOAP12 | HTTP)
httplocation="xs:string" -- {http location} property (SOAP11 | SOAP12 | HTTP)
httpignoreUncited="xs:boolean" -- {http location ignore uncited} property (SOAP11 | SOAP12 | HTTP)
httpqueryParameterSeparator="xs:string" -- cascading value for the {http query parameter separator} property (SOAP11 | SOAP12 | HTTP)
httpinputSerialization="xs:string" -- {http input serialization} property (HTTP)
>
<soapheader for="xs:string" -- operation name
required="xs:boolean"
mustUnderstand="xs:boolean"
type="xs:NCName"
type-namespace="xs:anyURI" > *
<httpheader for="xs:string"
required="xs:boolean"
type="xs:NCName"
type-namespace="xs:anyURI" > *
</binding-details> ?
</operation> +
</operations>
</service> +
</services>
The Signature Model Structure
The Signature model structure corresponding to different schema constructs are described with examples in here. http://wso2.org/wiki/display/commons/Signature Model Structure for Different Schema Constructs
Status and code
The current code artifacts are:
wsdl2sig.xslt
This stylesheet for converting a WSDL 2 document to the signature metafile format. The stylesheet generates a list of service descriptors for each endpoint in the service.
Currently it extracts signatures from a WSDL as follows:
- wrpc:signature: If an operation is annotated with wrpc:signature, these hints will be used to generate parameter names and types.
- Wrap and contain: If the schema defines a wrapper element which defines a local complexType which is a sequence of elements, each of those elements will be treated as a parameter (minOccurs, maxOccurs, nillable are all supported).
- Wrap and reference: If the schema defines a wrapper element which refers to a complexType which is a sequence of elements, those elements will be treated as above.
jsstub.xslt
This stylesheet converts the signature metaformat into a Javascript or E4X stub. The stub defines an object with the same name as the service, with methods corresponding to each operation. It unwraps the arrays and the built-in XML Schema simple types and converts them to their corresponding Javascript type as defined below. The stub also includes copy-and-pasteable invocations to jumpstart development. It does not support simple types based on restrictions of the built-in schema types at this point.
The stylesheet accepts the following parameters:
- service -- the name of the service to generate signatures for. If unspecified, the first service is used. This parameter will become useful when the signature metafile is augmented with binding details.
tryit.xslt
This stylesheet generates an ajax client appropriate to exercising the service.
XSD to Javascript Type Conversion
The following table shows how the XSD simple types map into Javascript types.
| string |
number |
boolean |
Date |
Array of strings |
Object |
| xs:string |
xs:float |
xs:boolean |
xs:dateTime (yyyy, mm, dd, hh:mm:ss, tz) |
xs:NMTOKENS |
xs:QName (E4X Qname object consisting of name, prefix, local-name, namespace-uri) |
| xs:normalizedString |
xs:double |
|
xs:date (yyyy, mm, dd, 0:00:00, tz) |
xs:IDREFS |
xs:anyType (XML object) |
| xs:token |
xs:integer |
|
xs:time (1970, 1, 1, hh:mm:ss, tz) |
xs:ENTITIES |
|
| xs:language |
xs:nonPositiveInteger |
|
xs:gYearMonth (yyyy, mm, 1, 0:00:00, tz) |
|
|
| xs:Name |
xs:negativeInteger |
|
xs:gMonthDay (1970, mm, dd, 0:00:00, tz) |
|
|
| xs:NCName |
xs:long |
|
xs:gYear (yyyy, 1, 1, 0:00:00, tz) |
|
|
| xs:ID |
xs:int |
|
xs:gDay (1970, 1, dd, 0:00:00, tz) |
|
|
| xs:IDREF |
xs:short |
|
xs:gMonth (1970, mm, 1, 0:00:00, tz) |
|
|
| xs:NMTOKEN |
xs:byte |
|
|
|
|
| xs:ENTITY |
xs:nonNegativeInteger |
|
|
|
|
| xs:anyURI |
xs:unsignedLong |
|
|
|
|
| xs:hexBinary |
xs:unsignedInt |
|
|
|
|
| xs:base64Binary |
xs:unsignedShort |
|
|
|
|
| xs:decimal |
xs:unsignedByte |
|
|
|
|
| xs:NOTATION |
xs:positiveInteger |
|
|
|
|
| |
xs:duration (in milliseconds) |
|
|
|
|
Note that the xs:duration conversion to milliseconds is broken because it could include a month which is not convertible deterministically to milliseconds. Needs more thought.