Description du langage WSDL (Web Services Description Language)

Carlos C. Tapang
Infotects

Résumé : grâce au langage WSDL, les utilisateurs peuvent automatiser la génération de proxy pour les services Web de façon totalement indépendante de la plate-forme et de la langue.

Sommaire

Pourquoi le langage WSDL ?
Structure des documents WSDL
Exemple de fichier WSDL
Espaces de noms
Messages SOAP
Schéma XML dans les sections Types et Messages du langage WSDL
Éléments <portType> et <operation>
Éléments <binding> et <operation>
Liaison au style des documents
Éléments <service> et <port>
Résumé
Ressources

Pourquoi le langage WSDL ?

Les normes telles qu'Internet Protocol (IP) sont-elles imposées par une administration quelconque ou est-ce que les gens les ont imposées eux-mêmes parce que les avantages qui en résultent compensent largement le coût de la compatibilité ? Beaucoup de normes ont été proposées et ne se sont pas développées. Parfois même, des normes qui ne se développent pas beaucoup sont pourtant renforcées par des lois ou des réglementations officielles : le langage de programmation Ada en est un exemple.

Je pense que ce sont les avantages résultant de l'adoption d'une norme qui font que cette norme est largement acceptée. Par exemple, pour une compagnie ferroviaire, l'important est que les rails construits par différentes entreprises s'adaptent les uns aux autres, ou que les produits de différentes entreprises fonctionnent ensemble. Plusieurs fournisseurs ont rassemblé leurs efforts pour établir SOAP comme une norme standard. Le langage WSDL (Web Services Description Language) permet de tirer les bénéfices de SOAP en offrant la possibilité aux fournisseurs et aux utilisateurs de services Web de fonctionner ensemble facilement. Il est simple pour des constructeurs de rails de fournir des rails qui vont ensemble : tout ce qu'ils ont à faire consiste à se mettre d'accord sur la distance entre les deux rails. Pour les services Web, c'est beaucoup plus complexe. La première chose à définir est un format standard pour spécifier les interfaces.

Il a été décidé que SOAP n'a pas vraiment besoin d'être accompagné d'un langage de description d'interface. Si SOAP constitue une norme pour communiquer du contenu pur, il doit alors avoir un langage pour décrire ce contenu. Les messages SOAP transportent des informations de type, ce qui fait que SOAP autorise la détermination dynamique du type. Mais je ne peux pas appeler correctement une fonction tant que je n'en connais pas le nom ni le nombre de paramètres et le type de chacun d'entre eux. Sans le langage WSDL, je peux deviner la syntaxe d'appel à partir de la documentation qui doit être fournie, ou en examinant les messages en ligne. D'une manière ou d'une autre, une intervention humaine sera nécessaire, ce qui ouvre la porte à des erreurs. Grâce au langage WSDL, je peux automatiser la génération de proxy pour les services Web de façon totalement indépendante de la plate-forme et de la langue. De même que pour le fichier IDL pour COM et CORBA, un fichier WSDL est un contrat entre le client et le serveur.

Notez que, bien que le langage WSDL ait été conçu pour exprimer les liaisons à des protocoles autres que SOAP, notre attention dans ce document sera portée sur le langage WSDL dans le cadre de sa relation à SOAP via HTTP. En outre, bien que SOAP soit actuellement utilisé principalement pour les appels de procédure ou de fonction distants, le langage WSDL permet de spécifier des documents pour une transmission sous SOAP. WSDL 1.1 a été envoyé au W3C sous forme de NOTE (voir http://www.w3.org/TR/wsdl.html Lien non Microsoft Site en anglais).

Structure des documents WSDL

Pour comprendre n'importe quel document XML, il est toujours utile d'avoir un organigramme. Le diagramme ci-dessous illustre la structure du langage WSDL, qui est un document XML, en décrivant les relations entre les cinq sections constituant un document WSDL.

Le document WSDL peut être divisé en deux groupes de sections. Le groupe du haut est constitué des définitions abstraites, tandis que le groupe du bas contient les descriptions concrètes. Les sections abstraites définissent les messages SOAP de façon totalement indépendante de la plate-forme et de la langue ; elles ne contiennent aucun élément spécifique à la langue ou à la machine. Cela facilite la définition d'un ensemble de services pouvant être implémenté par différents sites Web. Les questions spécifiques au site, telles que la sérialisation, sont reléguées dans les sections du bas, qui contiennent les descriptions concrètes.

  • Définitions abstraites
    • Types
      Définitions de type indépendantes de la langue et de la machine.
    • Messages
      Contient les paramètres de fonction (entrées séparées des sorties) ou les descriptions de document.
    • PortTypes
      Réfère aux définitions de message de la section Messages pour décrire les signatures de fonction (nom d'opération, paramètres d'entrée, paramètres de saisie).
  • Descriptions concrètes
    • Bindings
      Indique la (les) liaison(s) de chaque opération dans la section PortTypes.
    • Services
      Indique les adresses de port de chaque liaison.

Dans le diagramme ci-dessous, les connecteurs des flèches représentent les relations entre les différentes sections du document. Le connecteur point et flèche représente une relation "réfère à" ou "utilise". Le connecteur double flèche représente quant à lui une relation "modificateur". Enfin, le connecteur flèche 3D représente une relation "contient". Ainsi, la section Messages utilise des définitions de la section Types, la section PortTypes utilise des définitions de la section Messages, la section Bindings réfère à la section PortTypes et la section Services réfère à la section Bindings. Les sections PortTypes et Bindings contiennent des éléments d'opération et la section Services des éléments de port. Les éléments d'opération de la section PortTypes sont modifiés ou décrits plus précisément par les éléments d'opération de la section Bindings.

Dans ces notes documentaires, j'utiliserai la terminologie XML standard pour décrire le document WSDL. Le mot "élément" se rapporte à un élément XML et le mot "attribut" à un attribut d'élément. Par exemple :

<attribut d'élément="attribut-valeur">contenu</élément>

Le contenu peut également être constitué d'un ou de plusieurs éléments, de manière récursive. L'élément racine est l'élément le plus en haut auquel appartiennent tous les autres éléments d'un document. Un élément enfant appartient toujours à un autre élément, appelé élément parent.

Notez qu'il ne peut y avoir qu'une section Types ou pas de section Types du tout. Toutes les autres sections peuvent contenir zéro, un ou plusieurs éléments parents. Par exemple, la section Messages peut avoir zéro, un ou plusieurs éléments <message>. Le schéma WSDL requiert que toutes les sections s'affichent dans un ordre spécifique : import, types, message, portType, binding et service. Chaque section abstraite peut se trouver d'elle-même dans un fichier distinct et importée dans le document principal.

Figure 1.
figure 1. Définitions abstraites et concrètes

Exemple de fichier WSDL

Penchons-nous directement sur un exemple de fichier WSDL afin d'en comprendre la structure et le fonctionnement. Rappelez-vous qu'il s'agit d'un exemple extrêmement simple de document WSDL. Dans le cas présent, notre objectif se limite à illustrer ses fonctionnalités les plus évidentes. Les sections suivantes intègrent des descriptions plus détaillées.

<?xml version="1.0" encoding="UTF-8" ?>
<definitions name="FooSample"
targetNamespace="http://tempuri.org/wsdl/"
xmlns:wsdlns="http://tempuri.org/wsdl/"
xmlns:typens="http://tempuri.org/xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:stk="http://schemas.microsoft.com/soap-toolkit/wsdl-extension"
xmlns="http://schemas.xmlsoap.org/wsdl/">

<types>
<schema targetNamespace="http://tempuri.org/xsd" 
xmlns="http://www.w3.org/2001/XMLSchema" 
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
elementFormDefault="qualified" >
</schema>
</types>

<message name="Simple.foo">
<part name="arg" type="xsd:int"/>
</message>

<message name="Simple.fooResponse">
<part name="result" type="xsd:int"/>
</message>

<portType name="SimplePortType">
<operation name="foo" parameterOrder="arg" >
<input message="wsdlns:Simple.foo"/>
<output message="wsdlns:Simple.fooResponse"/>
</operation>
</portType>

<binding name="SimpleBinding" type="wsdlns:SimplePortType">
<stk:binding preferredEncoding="UTF-8" />
<soap:binding style="rpc" 
 transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="foo">
<soap:operation
soapAction="http://tempuri.org/action/Simple.foo"/>
<input>
<soap:body use="encoded" namespace="http://tempuri.org/message/" 
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</input>
<output>
<soap:body use="encoded" namespace="http://tempuri.org/message/" 
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
</operation>
</binding>

<service name="FOOSAMPLEService">
<port name="SimplePort" binding="wsdlns:SimpleBinding">
<soap:address location="http://carlos:8080/FooSample/FooSample.asp"/>
</port>
</service>
</definitions>

Ce qui suit est une vue d'ensemble de l'exemple de document. Je traiterai chaque section plus en détail ultérieurement.

La première ligne déclare que le document est du langage XML. Bien que ce ne soit pas requis, cela aide l'analyseur XML à déterminer si le fichier WSDL doit être analysé ou s'il doit signaler une erreur. La deuxième ligne est l'élément racine du document WSDL : <définitions>. Il existe plusieurs attributs d'espace de noms (déclarations d'espace de noms) attachés à l'élément racine, de même que dans l'élément enfant <schema> de l'élément <types>.

L'élément <types> comprend la section Types. Cette section peut être omise ni aucun type de données n'a besoin d'être déclaré. Dans l'exemple de fichier WSDL, il n'y a aucun type spécifique à l'application déclaré mais j'utilise quand même la section Types pour déclarer les espaces de noms de schéma utilisés dans le document.

Les éléments <message> comprennent la section Messages. Si nous envisageons les opérations comme des fonctions, alors un élément <message> définit les paramètres pour cette fonction. Chaque élément enfant <part> de l'élément <message> correspond à un paramètre. Les paramètres d'entrée sont définis dans un élément <message> unique et séparés des paramètres de sortie, qui se trouvent dans leur propre élément <message>. Les paramètres qui sont à la fois des paramètres d'entrée et de sortie possèdent leurs éléments <part> correspondants dans les éléments <message> d'entrée et de sortie. Par convention, le nom d'un élément <message> de sortie se termine par "Response", comme dans "fooResponse". Chaque élément <part> a un attribut de nom et de type, tout comme un paramètre de fonction a un nom et un type.

Lorsqu'il est utilisé pour l'échange de document, le langage WSDL autorise l'utilisation d'éléments <message> pour décrire le document à échanger.

Le type d'un élément <part> peut être un type de base XSD, un type défini par SOAP (soapenc), un type défini par WSDL (wsdl) ou un type défini par la section Types.

La section PortTypes peut contenir zéro, un ou plusieurs éléments <portType>. Les définitions PortType abstraites pouvant être placées dans un fichier distinct, il est possible de n'avoir aucun élément <portType> dans un fichier WSDL. L'exemple ci-dessus contient uniquement un élément <portType>. Comme vous pouvez le voir, un élément <portType> définit une ou plusieurs opérations dans les éléments <operation>. L'exemple n'indique qu'un élément <operation>, nommé "foo". Ce nom équivaut à un nom de fonction. L'élément <operation> peut posséder un, deux ou trois éléments enfants : les éléments <input> (entrée), <output> (sortie) et <fault> (erreur). L'attribut de message de chaque élément <input> et <output> réfère à l'élément <message> correspondant dans la section Messages. Ainsi, l'ensemble de l'élément <portType> de l'exemple équivaut à la déclaration de fonction C suivante :

int foo(int arg);

Cet exemple démontre comment le langage XML est bien plus volumineux que le langage C (y compris les éléments <message> : dans l'exemple, 12 lignes de XML ont été nécessaires pour exprimer la même déclaration de fonction à une seule ligne).

La section Bindings peut avoir zéro, un ou plusieurs éléments <binding>. Sa fonction consiste à spécifier comment les appels et réponses d'élément <operation> sont envoyés et transmis. La section Services peut elle aussi posséder zéro, un ou plusieurs éléments <service>. Elle contient des éléments <port>, lesquels réfèrent chacun à un élément <binding> de la section Bindings. Les sections Bindings et Services comprennent toutes les deux les descriptions concrètes d'un document WSDL.

Espaces de noms

Il y a des attributs d'espace de noms à la fois dans l'élément racine <definitions> et dans l'élément enfant <schema> :

<definitions name="FooSample"
targetNamespace="http://tempuri.org/wsdl/"
xmlns:wsdlns="http://tempuri.org/wsdl/"
xmlns:typens="http://tempuri.org/xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:stk="http://schemas.microsoft.com/soap-toolkit/wsdl-extension"
xmlns="http://schemas.xmlsoap.org/wsdl/">

<types>
<schema targetNamespace="http://tempuri.org/xsd" 
xmlns="http://www.w3.org/2001/XMLSchema" 
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
elementFormDefault="qualified" >
</schema>
</types>

Chaque attribut d'espace de noms déclare un alias pour chaque espace de noms utilisé dans le document. Par exemple, "xmlns:xsd" définit un alias (xsd) pour l'espace de noms http://www.w3.org/2001/XMLSchema Lien non Microsoft Site en anglais. Cela permet de faire référence à cet espace de noms plus loin dans le document en ajoutant simplement le préfixe (ou en "qualifiant") "xsd:" à un nom, comme dans "xsd:int" qui constitue alors un nom de type qualifié. Les règles d'étendue classiques s'appliquent aux préfixes d'alias. C'est-à-dire qu'un préfixe défini dans un élément n'est valable que dans cet élément.

Quelle est l'utilité des espaces de noms ? Le but des espaces de noms est d'éviter les conflits de noms. Si j'établis un service Web dont le fichier WSDL contient un élément avec le nom "foo" et que vous souhaitez utiliser mon service Web conjointement avec un autre service complémentaire, cet autre service, sans les espaces de noms, ne pourrait pas utiliser le nom "foo" où que ce soit dans son fichier WSDL. Les deux services peuvent utiliser le même nom uniquement s'il signifie exactement la même chose dans les deux. Avec deux espaces de noms distincts, le "foo" de mon service Web peut signifier autre chose que le "foo" de l'autre service Web. Dans votre client, vous devez également référer à mon "foo" en le qualifiant. Par exemple, http://www.infotects.com/fooService\#fo est un nom totalement qualifié qui peut être équivalent à "carlos:foo" si je déclare carlos comme un alias pour http://www.infotects.com/fooService. Notez que les URL sont utilisées afin de s'assurer que les espaces de noms sont uniques mais également pour autoriser les adresses dans le document. L'emplacement vers lequel l'URL pointe ne doit pas forcément correspondre à un emplacement Web réel. Un GUID peut également être utilisé à la place de l'URL ou en complément de celle-ci. Par exemple, le GUID "335DB901-D44A-11D4-A96E-0080AD76435D" constitue un désignateur d'espace de noms valide.

L'attribut targetNamespace déclare un espace de noms auquel tous les noms déclarés dans un élément appartiennent. Dans l'exemple de fichier WSDL, l'attribut targetNamespace pour <definitions> est http://tempuri.org/wsdl. Ceci signifie que tous les noms déclarés dans ce document WSDL appartiennent à cet espace de noms. L'élément <schema> possède son propre attribut targetNamespace avec pour valeur http://tempuri.org/xsd de sorte que tous les noms définis dans cet élément <schema> appartiennent à cet espace de noms plutôt qu'à l'espace de noms principal.

La ligne suivante de l'élément <schema> déclare un espace de noms par défaut. Tous les noms non qualifiés du schéma appartiennent à cet espace de noms.

xmlns="http://www.w3.org/2001/XMLSchema" 

Messages SOAP

Un fichier WSDL peut être envisagé, entre autres, comme un moyen, pour les clients et serveurs qui l'utilisent, de savoir ce qui est envoyé sur le réseau. Bien que SOAP utilise des protocoles de faible niveau tels qu'IP et HTTP, l'application détermine le protocole haut niveau qu'elle utilise entre un client et un serveur donnés. En d'autres termes, si l'on prend une opération, par exemple "echoInt" qui se limite à reproduire un entier en entrée, le nombre de paramètres, le type de chaque paramètre et la manière dont ces paramètres doivent être envoyés par le réseau (sérialisation) constituent un protocole spécifique à l'application. Un tel protocole peut être spécifié de nombreuses manières, et je pense que la meilleure d'entre elles est le langage WSDL. Si nous l'envisageons ainsi, le langage WSDL ne constitue pas simplement un "contrat d'interface" ; il s'agit également d'un langage de spécification de protocole. C'est précisément ce dont nous avons besoin si nous devons aller au-delà des protocoles "figés", tels qu'IP et HTTP, et considérer des protocoles spécifiques aux applications.

Le langage WSDL peut indiquer si les messages SOAP sont conformes aux styles du RPC (appel de procédure distante) ou bien à ceux du document. Un message du style du RPC, comme dans l'exemple, ressemble à un appel de fonction avec zéro paramètres ou plus. Un message du style du document est plus plat et requiert moins de niveaux d'imbrication. Les messages XML ci-dessous sont envoyés et reçus en tant que résultat de l'analyse de l'exemple de fichier WSDL en utilisant les objets SoapClient dans MS SOAP Toolkit 2.0 (MSTK2).

Envoyé à partir du client pour réaliser un appel de fonction "foo(5131953)" :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope 
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<m:foo xmlns:m="http://tempuri.org/message/">
<arg>5131953</arg>
</m:foo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Reçu en retour du serveur (réponse) :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope 
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAPSDK1:fooResponse xmlns:SOAPSDK1="http://tempuri.org/message/">
<result>5131953</result>
</SOAPSDK1:fooResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Le message d'appel de fonction et sa réponse constituent tous les deux du langage XML valide. Un message SOAP consiste en un élément <Envelope> contenant un élément <Header> facultatif et au moins un élément <body>. Les messages envoyés et reçus ont tous les deux un élément <Body> unique dans l'élément <Envelope>. Le corps du message d'appel de fonction de RPC possède un élément nommé après le nom d'opération "foo", tandis que le corps de la réponse possède un élément "fooResponse". L'élément foo comporte une partie, <arg>, qui est l'argument unique, tel que le décrit l'exemple de fichier WSDL. L'élément fooResponse possède de la même manière une partie <result> unique. Notez comment l'espace de noms d'encodingStyle, de l'enveloppe et du message est répété ici tel que la section Bindings du fichier WSDL l'a d'abord prescrit :

<binding name="SimpleBinding" type="wsdlns:SimplePortType">
 <stk:binding preferredEncoding="UTF-8" />
 <soap:binding style="rpc" 
  transport="http://schemas.xmlsoap.org/soap/http"/>
 <operation name="foo">
 <soap:operation
 soapAction="http://tempuri.org/action/Simple.foo"/>
 <input>
  <soap:body use="encoded" 
  namespace="http://tempuri.org/message/" 
  encodingStyle=
  "http://schemas.xmlsoap.org/soap/encoding/" />
 </input>
 <output>
  <soap:body use="encoded" 
  namespace="http://tempuri.org/message/" 
  encodingStyle=
  "http://schemas.xmlsoap.org/soap/encoding/" />
 </output>
 </operation>
 </binding>

Schéma XML dans les sections Types et Messages du langage WSDL

La saisie de données WSDL est basée sur "XML Schema: Datatypes" (XSD) qui est désormais une recommandation de W3C. Il existe trois versions différentes de ce document (1999, 2000/10 et 2001), et le fait de le déclarer comme l'un des attributs d'espace de noms dans l'élément <definitions> permet de préciser quelle version est utilisée dans un fichier WSDL donné :

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

Dans cet article, nous nous intéresserons à la version 2001 uniquement. Les partisans de la norme WSDL recommandent fortement l'utilisation de la norme 2001.

Dans cette section et celles qui suivent, les préfixes ou alias d'espace de noms suivants sont utilisés :

Préfixe Espace de noms équivalent Description
soapenc http://schemas.xmlsoap.org/soap/encoding Codage SOAP 1.1
wsdl http://schemas.xmlsoap.org/wsdl/soap WSDL 1.1
xsd http://www.w3.org/2001/XMLSchema Schéma XML

Types de base XSD

Le tableau suivant, qui provient directement de la documentation de MSTK2, énumère tous les types de base XSD pris en charge par MSTK2. Il montre comment le lecteur WSDL, côté client comme côté serveur, fait correspondre les types XSD à des types de Variant et aux types correspondants en VB, C++ et IDL.

Type XSD (Soap) Type de Variant VB C++ IDL Commentaires
anyURI VT_BSTR String BSTR BSTR  
base64Binary VT_ARRAY | VT_UI1 Byte() SAFEARRAY SAFEARRAY(unsigned char)  
boolean VT_BOOL Boolean VARIANT_BOOL VARIANT_BOOL  
byte VT_I2 Integer short short Plage validée à la conversion.
date VT_DATE Date DATE DATE Heure définie à 00:00:00
dateTime VT_DATE Date DATE DATE  
double VT_R8 Double double double  
duration VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
ENTITIES VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
ENTITY VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
float VT_R4 Single float float  
gDay VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
gMonth VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
gMonthDay VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
gYear VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
gYearMonth VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
ID VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
IDREF VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
IDREFS VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
int VT_I4 Long long long  
integer VT_DECIMAL Variant DECIMAL DECIMAL  Plage validée à la conversion.
language VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
long VT_DECIMAL Variant DECIMAL DECIMAL  Plage validée à la conversion.
Name VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
NCName VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
negativeInteger VT_DECIMAL Variant DECIMAL DECIMAL  Plage validée à la conversion.
NMTOKEN VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
NMTOKENS VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
nonNegativeInteger VT_DECIMAL Variant DECIMAL DECIMAL  Plage validée à la conversion.
nonPositiveInteger VT_DECIMAL Variant DECIMAL DECIMAL  Plage validée à la conversion.
normalizedString VT_BSTR String BSTR BSTR  
NOTATION VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
number VT_DECIMAL Variant DECIMAL DECIMAL  
positiveInteger VT_DECIMAL Variant DECIMAL DECIMAL  Plage validée à la conversion.
QName VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
short VT_I2 Integer short short  
string VT_BSTR String BSTR BSTR  
time VT_DATE Date DATE DATE Jour défini au 30 décembre 1899
token VT_BSTR String BSTR BSTR Pas de validation ou de conversion réalisée
unsignedByte VT_UI1 Byte unsigned char unsigned char  
unsignedInt VT_DECIMAL Variant DECIMAL DECIMAL  Plage validée à la conversion.
unsignedLong VT_DECIMAL Variant DECIMAL DECIMAL  Plage validée à la conversion.
unsignedShort VT_UI4 Long Long Long  Plage validée à la conversion.

XSD définit deux ensembles de types de données intégrés : les primitives et les dérivées. Vous pouvez en savoir plus sur la hiérarchie des types de données intégrés à l'adresse http://www.w3.org/TR/2001/PR-xmlschema-2-20010330 Lien non Microsoft Site en anglais.

Types complexes

Le schéma XML autorise la définition de types complexes, ce qui, en langage C, constituerait des structures. Par exemple, pour définir l'équivalent de la structure de langage C suivante :

typedef struct {
 string firstName;
 string lastName;
 long ageInYears;
 float weightInLbs;
 float heightInInches;
} PERSON;

nous pouvons écrire le schéma XML suivant :

<xsd:complexType name="PERSON">
 <xsd:sequence>
 <xsd:element name="firstName" type="xsd:string"/>
 <xsd:element name="lastName" type="xsd:string"/>
 <xsd:element name="ageInYears" type="xsd:int"/>
 <xsd:element name="weightInLbs" type="xsd:float"/>
 <xsd:element name="heightInInches" type="xsd:float"/>
 </xsd:sequence>
</xsd:complexType>

En revanche, <complexType> peut exprimer bien plus que le simple équivalent d'une structure. Il peut comporter d'autres éléments enfants que <sequence>. Au lieu de <sequence>, j'aurais pu utiliser <all>:

<xsd:complexType name="PERSON">
 <xsd:all>
 <xsd:element name="firstName" type="xsd:string"/>
 <xsd:element name="lastName" type="xsd:string"/>
 <xsd:element name="ageInYears" type="xsd:int"/>
 <xsd:element name="weightInLbs" type="xsd:float"/>
 <xsd:element name="heightInInches" type="xsd:float"/>
 </xsd:all>
</xsd:complexType>

Ceci signifierait que les éléments <element> de la variable de membre peuvent apparaître dans n'importe quel ordre et que chacun d'eux est facultatif. Une structure en langage C n'aurait pas pu avoir exactement la même forme.

Notez l'utilisation des types de données intégrés string, int, float dans l'exemple. Une chaîne (string) en langage C est également une chaîne en XML, et une virgule flottante (float) est une virgule flottante. Mais long en langage C correspond à int en XML (comme dans le tableau ci-dessus).

Dans un fichier WSDL, les types complexes tels que celui qui est présenté ci-dessus, sont déclarés dans la section Types. Par exemple, je peux déclarer le type PERSON de la manière suivante et l'utiliser dans la section Messages :

<?xml version="1.0" encoding="UTF-8" ?>
<definitions … >
<types>
 <schema targetNamespace="someNamespace" 
 xmlns:typens="someNamespace" >
 <xsd:complexType name="PERSON">
 <xsd:sequence>
 <xsd:element name="firstName" type="xsd:string"/>
 <xsd:element name="lastName" type="xsd:string"/>
 <xsd:element name="ageInYears" type="xsd:int"/>
 <xsd:element name="weightInLbs" type="xsd:float"/>
 <xsd:element name="heightInInches" type="xsd:float"/>
 </xsd:sequence>
 </xsd:complexType>
 </schema>
</types>

<message name="addPerson">
 <part name="person" type="typens:PERSON"/>
</message>

<message name="addPersonResponse">
 <part name="result" type="xsd:int"/>
</message>

</definitions>

Dans l'exemple ci-dessus, le premier message porte le nom "addPerson" et possède un élément <part> dont le type est "PERSON". Le type PERSON est déclaré comme un type complexe dans la section Types.

Si nous utilisons un fichier WSDL complet avec le fragment ci-dessus lors de l'initialisation de MSTK2 SoapClient, celui-ci analysera le fichier correctement. Toutefois, il ne pourra pas envoyer un appel de fonction à <addPerson>. En effet, SoapClient ne sait pas comment traiter les types complexes de lui-même et il a besoin d'un mappeur de type personnalisé pour le faire. La documentation de MSTK2 comporte un exemple d'application incluant un mappeur de type personnalisé.

Il existe une autre méthode pour lier un élément <part> à une déclaration de type. Elle consiste à utiliser un élément plutôt qu'un attribut de type. Dans l'exemple suivant, je déclare deux éléments dans la section, "Person" (Personne) et "Gender" (Sexe), auxquels je fais référence ensuite dans l'élément <message> de "addPerson" à l'aide d'un attribut d'élément.

<?xml version="1.0" encoding="UTF-8" ?>
<definitions … >
<types>
 <schema targetNamespace="someNamespace" 
 xmlns:typens="someNamespace" >
 <element name="Person">
 <xsd:complexType>
 <xsd:sequence>
 <xsd:element name="firstName" type="xsd:string"/>
 <xsd:element name="lastName" type="xsd:string"/>
 <xsd:element name="ageInYears" type="xsd:int"/>
 <xsd:element name="weightInLbs" type="xsd:float"/>
 <xsd:element name="heightInInches" type="xsd:float"/>
 </xsd:sequence>
 </xsd:complexType>
 </element>
 <element name="Gender">
 <xsd:simpleType>
 <xsd:restriction base="xsd:string">
 <xsd:enumeration value="Male" />
 <xsd:enumeration value="Female" />
 </xsd:restriction>
 </xsd:simpleType>
 </element>
 </schema>
</types>

<message name="addPerson">
 <part name="who" element="typens:Person"/>
 <part name="sex" element="typens:Gender"/>
</message>

<message name="addPersonResponse">
 <part name="result" type="xsd:int"/>
</message>
</definitions>

L'élément Gender de la section Types l'a incorporé dans un type d'énumération anonyme dont les valeurs possibles sont "Male" et "Female". Je fais ensuite référence à cet élément dans l'élément <message> de "addPerson" en utilisant un attribut d'élément plutôt qu'un attribut de type.

Quelle est la différence entre les attributs d'élément et les attributs de type lorsque j'associe un type en particulier à un élément <part> ? Grâce à l'attribut de type, nous pouvons décrire une partie pouvant prendre en charge plusieurs types (comme un Variant), ce qui est impossible avec un attribut d'élément. L'exemple ci-dessous le montre.

<?xml version="1.0" encoding="UTF-8" ?>
<definitions … >
<types>
 <schema targetNamespace="someNamespace" 
 xmlns:typens="someNamespace">
 <xsd:complexType name="PERSON">
 <xsd:sequence>
 <xsd:element name="firstName" type="xsd:string"/>
 <xsd:element name="lastName" type="xsd:string"/>
 <xsd:element name="ageInYears" type="xsd:int"/>
 <xsd:element name="weightInLbs" type="xsd:float"/>
 <xsd:element name="heightInInches" type="xsd:float"/>
 </xsd:sequence>
 </xsd:complexType>
 <xsd:complexType name="femalePerson">
 <xsd:complexContent>
 <xsd:extension base="typens:PERSON" >
 <xsd:element name="favoriteLipstick" type="xsd:string" />
 </xsd:extension>
 </xsd:complexContent>
 </xsd:complexType>
 <xsd:complexType name="malePerson">
 <xsd:complexContent>
 <xsd:extension base="typens:PERSON" >
 <xsd:element name="favoriteShavingLotion" type="xsd:string" />
 </xsd:extension>
 </xsd:complexContent>
 </xsd:complexType>
 <xsd:complexType name="maleOrFemalePerson">
 <xsd:choice>
 <xsd:element name="fArg" type="typens:femalePerson" >
 <xsd:element name="mArg" type="typens:malePerson" />
 </xsd:choice>
 </xsd:complexType>
 </schema>
</types>

<message name="addPerson">
 <part name="person" type="typens:maleOrFemalePerson"/>
</message>

<message name="addPersonResponse">
 <part name="result" type="xsd:int"/>
</message>

</definitions>

L'exemple ci-dessus illustre en outre l'utilisation de la dérivation par extension. "femalePerson" et "malePerson" sont dérivés de "PERSON". Chacun possède un élément supplémentaire : "favoriteLipstick" pour "femalePerson" et "favoriteShavingLotion" pour "malePerson". Les deux types dérivés sont combinés dans un type complexe unique, "maleOrFemalePerson", à l'aide de la construction <choice>. Enfin, dans l'élément <message> de "addPerson", le type combiné est référencé par l'élément <part> de "person". Cet élément <part> ou paramètre peut ensuite être soit "femalePerson" ou "malePerson".

Tableaux

XSD propose la construction <list> pour déclarer un tableau d'éléments séparés par des espaces. En revanche, SOAP n'utilise pas de listes XSD pour coder ses tableaux. Au lieu de cela, il définit son propre type pour les tableaux, "SOAP-ENC:Array". L'exemple suivant montre comment dériver à partir de ce type pour déclarer un tableau à dimension unique de nombres entiers :

<xsd:complexType name="ArrayOfInt">
 <xsd:complexContent>
 <xsd:restriction base="soapenc:Array">
 <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:int[]"/>
 </xsd:restriction>
 </xsd:complexContent>
</xsd:complexType>

Un nouveau type complexe est déclaré en dérivant à partir de soapenc:Array et en utilisant la dérivation par restriction. Un attribut est ensuite déclaré pour le type complexe : l'attribut arrayType. La référence à "soapenc:arrayType" effectue en fait la déclaration de l'attribut arrayType de la manière suivante :

<xsd:attribute name="arrayType" type="xsd:string"/>

La valeur de l'attribut wsdl:arrayType détermine ensuite le type de chacun des membres du tableau. Les éléments du tableau peuvent également être de type complexe :

<xsd:complexType name="ArrayOfPERSON">
 <xsd:complexContent>
 <xsd:restriction base="soapenc:Array">
 <attribute ref="soapenc:arrayType" 
 wsdl:arrayType="typens:PERSON[]"/>
 </xsd:restriction>
 </xsd:complexContent>
</xsd:complexType>

Le langage WSDL requiert que le nom de type pour un tableau soit la concaténation de la chaîne "ArrayOf" et du type des éléments du tableau. Il est alors évident, à l'aide du nom à lui seul, que le tableau "ArrayOfPERSON" est un tableau de structures "PERSON". J'utilise ci-dessous ArrayOfPERSON pour déclarer un élément <message> pour l'ajout non pas d'une personne mais d'un certain nombre de personnes :

<?xml version="1.0" encoding="UTF-8" ?>
<definitions … >
<types>
 <schema targetNamespace="someNamespace" 
 xmlns:typens="someNamespace" >
 <xsd:complexType name="PERSON">
 <xsd:sequence>
 <xsd:element name="firstName" type="xsd:string"/>
 <xsd:element name="lastName" type="xsd:string"/>
 <xsd:element name="ageInYears" type="xsd:int"/>
 <xsd:element name="weightInLbs" type="xsd:float"/>
 <xsd:element name="heightInInches" type="xsd:float"/>
 </xsd:sequence>
 </xsd:complexType>
 <xsd:complexType name="ArrayOfPERSON">
 <xsd:complexContent>
 <xsd:restriction base="soapenc:Array">
 <attribute ref="soapenc:arrayType" 
 wsdl:arrayType="typens:PERSON[]"/>
 </xsd:restriction>
 </xsd:complexContent>
 </xsd:complexType>
 </schema>
</types>

<message name="addPersons">
 <part name="person" type="typens:ArrayOfPERSON"/>
</message>

<message name="addPersonResponse">
 <part name="result" type="xsd:int"/>
</message>

</definitions>

Éléments <portType> et <operation>

Un élément PortType définit un nombre d'opérations dans la définition abstraite. Les éléments <operation> dans un élément PortType définissent la syntaxe pour appeler toutes les méthodes de PortType. Chaque élément <operation> déclare le nom de la méthode, les paramètres (à l'aide d'éléments <message>) et les types de chacun d'entre eux (éléments <part> déclarés dans chaque <message>).

Un document WSDL peut comporter plusieurs éléments <portType>. Chaque élément <portType> regroupe un certain nombre d'opérations liées, un peu comme une interface COM regroupe un certain nombre de méthodes.

Dans un élément <operation>, il peut y avoir au maximum un élément <input>, un élément <output> et un élément <fault>. Chacun de ces trois éléments possède un attribut de nom et de message.

Quelle est la fonction d'un attribut de nom dans les éléments <input>, <output> et <fault> ? Il permet de distinguer deux opérations portant le même nom (surcharge). Par exemple, examinez les deux fonctions en langage C suivantes, avec le même nom mais des paramètres différents :

void foo(int arg);
void foo(string arg);

Ce type de surcharge peut également être exprimée en WSDL :

<?xml version="1.0" encoding="UTF-8" ?>
<definitions name="fooDescription"
 targetNamespace="http://tempuri.org/wsdl/"
 xmlns:wsdlns="http://tempuri.org/wsdl/"
 xmlns:typens="http://tempuri.org/xsd"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:stk="http://schemas.microsoft.com/soap-toolkit/wsdl-
 extension"
 xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
 <schema targetNamespace="http://tempuri.org/xsd"
 xmlns="http://www.w3.org/2001/XMLSchema" 
 xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 elementFormDefault="qualified" >
</schema>
</types>

<message name="foo1">
 <part name="arg" type="xsd:int"/>
</message>

<message name="foo2">
 <part name="arg" type="xsd:string"/>
</message>

<portType name="fooSamplePortType">
 <operation name="foo" parameterOrder="arg " >
 <input name="foo1" message="wsdlns:foo1"/>
 </operation>
 <operation name="foo" parameterOrder="arg " >
 <input name="foo2" message="wsdlns:foo2"/>
 </operation>
</portType>

<binding name="fooSampleBinding" type="wsdlns:fooSamplePortType">
<stk:binding preferredEncoding="UTF-8" />
 <soap:binding style="rpc" 
 transport="http://schemas.xmlsoap.org/soap/http"/>
 <operation name="foo">
 <soap:operation soapAction="http://tempuri.org/action/foo1"/>
 <input name="foo1">
 <soap:body use="encoded" namespace="http://tempuri.org/message/" 
 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
 </input>
</operation>
<operation name="foo">
 <soap:operation soapAction="http://tempuri.org/action/foo2"/>
 <input name="foo2">
 <soap:body use="encoded" 
 namespace="http://tempuri.org/message/" 
 encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" 
 />
 </input>
</operation>
</binding>

 <service name="FOOService">
 <port name="fooSamplePort" binding="fooSampleBinding">
 <soap:address 
  location="http://carlos:8080/fooService/foo.asp"/>
 </port>
 </service>
</definitions>

Au moment où nous écrivons cet article, aucune implémentation de SOAP n'a été en mesure de réaliser la surcharge des noms d'opération. Cela est important pour les clients basés sur Java car les serveurs Java utilisent des interfaces qui font appel à la fonctionnalité de surcharge de Java. Pour les clients basés sur COM, ce n'est pas important car COM ne prend pas en charge la surcharge.

Éléments <binding> et <operation>

La section Binding est l'endroit où le protocole, la sérialisation et le codage sur le réseau sont entièrement spécifiés. Tandis que les sections Types, Messages et PortType utilisent les données des définitions abstraites, la section Binding est l'endroit où les détails physiques de la transmission des données sont traités. Elle concrétise les définitions abstraites réalisées dans les trois premières sections.

Le fait de séparer les spécifications de liaison des déclarations de données et de messages signifie que les fournisseurs de services qui se lancent sur un même type d'activité peuvent normaliser un ensemble d'opérations (portType). Chaque fournisseur peut ensuite se distinguer des autres en proposant des liaisons personnalisées. WSDL possédant également une construction d'importation, cela permet de placer les définitions abstraites dans leur propre fichier, séparé des sections Bindings et Services, pour pouvoir les distribuer entre les fournisseurs de services pour lesquels les définitions abstraites auront été établies comme une norme. Par exemple, les banques peuvent se mettre d'accord pour normaliser un ensemble d'opérations bancaires, qui sont ensuite décrites en détail dans un document WSDL de définitions abstraites. Chaque banque est libre ensuite de "personnaliser" le protocole sous-jacent, les optimisations de sérialisation et le codage.

Ci-dessous se trouve de nouveau la section Binding de l'exemple de surcharge WSDL afin que je puisse en traiter les détails :

<binding name="fooSampleBinding" type="wsdlns:fooSamplePortType">
 <stk:binding preferredEncoding="UTF-8" />
 <soap:binding style="rpc" 
 transport="http://schemas.xmlsoap.org/soap/http"/>
 <operation name="foo">
 <soap:operation soapAction="http://tempuri.org/action/foo1"/>
 <input name="foo1">
  <soap:body use="encoded" 
  namespace="http://tempuri.org/message/" 
  encodingStyle=
  "http://schemas.xmlsoap.org/soap/encoding/" />
 </input>
 </operation>
 <operation name="foo">
 <soap:operation soapAction="http://tempuri.org/action/foo2"/>
 <input name="foo2">
  <soap:body use="encoded" 
  namespace="http://tempuri.org/message/" 
  encodingStyle=
  "http://schemas.xmlsoap.org/soap/encoding/" />
 </input>
 </operation>
</binding>

Un nom est attribué à l'élément <binding> (en l'occurrence "fooSampleBinding") de sorte que l'élément <port> de la section Services puisse y référer. Il possède un attribut de type qui réfère à <portType>, dans le cas présent "wsdlns:fooSamplePortType". La deuxième ligne est un élément d'extension MSTK2, <stk:binding>, qui indique le codage préféré (preferredEncoding), "UTF-8".

L'élément <soap:binding> spécifie le style ("rpc") et le transport utilisés. L'attribut de transport réfère à un espace de noms, ce qui signifie que le protocole SOAP HTTP est utilisé.

Il y a deux éléments <operation> portant le même nom : "foo". Ce qui distingue les deux opérations, ce sont les deux noms d'élément <input> différents : "foo1" et "foo2". L'élément <soap:operation> porte le même attribut soapAction dans les deux éléments <operation>; il s'agit en réalité d'une URI. L'attribut soapAction est une URI spécifique à SOAP, qui est tout simplement utilisée dans la formulation du message SOAP. Le message SOAP résultant possède un en-tête SOAPAction et cette URI dans l'élément <soap:operation> en devient la valeur. L'attribut soapAction est requis pour la liaison HTTP mais ne doit pas être présent pour la liaison autre que HTTP. Son utilisation est encore floue au moment de la rédaction de cet article. Il semble qu'il peut être utilisé pour distinguer les deux opérations "foo" dans ce cas précis. SOAP 1.1 établit que soapAction est utilisé pour identifier "l'intention" du message. On suppose que le serveur peut utiliser cet attribut pour acheminer le message sans avoir besoin de l'analyser dans sa totalité. Dans la pratique, son utilisation varie. L'élément <soap:operation> peut également contenir un autre attribut, l'attribut "style", utilisé le cas échéant pour ignorer le style spécifié dans l'élément <soap:binding> pour cette opération en particulier.

L'élément <operation> peut contenir les éléments <input>, <output> et <fault>, qui correspondent aux élément du même nom dans la section PortTypes. Seul l'élément <input> est présent dans l'exemple ci-dessus. Chacun de ces trois éléments possède un attribut de nom facultatif pouvant être utilisé, comme dans le cas présent, pour distinguer des opérations portant le même nom. Dans l'élément <input> de l'exemple, il se trouve un élément <soap:body> qui spécifie les données de l'élément <body> du message SOAP résultant. Cet élément possède les attributs suivants :

  • Use
    Ceci permet de spécifier si les données sont codées ou littérales. "Literal" (littérales) signifie que le message SOAP résultant contient les données formatées exactement comme dans les définitions abstraites (sections Types, Messages et PortTypes). "Encoded" (codées) signifie que l'attribut encodingStyle (voir ci-dessous) décide du codage.
  • Namespace
    Chaque corps de message SOAP peut avoir son propre espace de noms pour éviter les problèmes de noms. L'URI spécifiée dans cet attribut est utilisée telle quelle dans le message SOAP résultant.
  • EncodingStyle
    Pour le codage SOAP, cet attribut doit avoir la valeur d'URI "http://schemas.xmlsoap.org/soap/encoding".

Liaison au style des documents

Dans la section précédente, l'élément <soap:binding> possède un attribut de style, défini à "rpc". Cet attribut, lorsqu'il est défini à "document", modifie la sérialisation des message sur le réseau. Au lieu des signatures de fonction, les messages sont alors des transmissions de document. Dans ce type de liaison, les éléments <message> définissent les formats de documents plutôt que les signatures de fonction. Prenons pour exemple le fragment WSDL suivant :

<definitions
 xmlns:stns="(SchemaTNS)"
 xmlns:wtns="(WsdlTNS)"
 targetNamespace="(WsdlTNS)">

<schema targetNamespace="(SchemaTNS)"
 elementFormDefault="qualified">
 <element name="SimpleElement" type="xsd:int"/>
 <element name="CompositElement" type="stns:CompositeType"/>
 <complexType name="CompositeType">
 <all>
 <element name='a' type="xsd:int"/>
 <element name='b' type="xsd:string"/>
 </all>
 </complexType>
</schema>

<message...>
 <part name='p1' type="stns:CompositeType"/>
 <part name='p2' type="xsd:int"/>
 <part name='p3' element="stns:SimpleElement"/>
 <part name='p4' element="stns:CompositeElement"/>
</message>
…
</definitions>

Le schéma possède deux éléments, SimpleElement et CompositeElement, et un type déclaré (CompositeType). Le seul élément <message> déclaré a quatre parties : p1, du type CompositeType ; p2, du type int ; p3, qui est un SimpleElement ; et p4, qui est un CompositeElement. Le tableau ci-dessous compare quatre sortes de liaisons, déterminées par utilisation/type : rpc/littéral, document/littéral, rpc/codé et document/codé. Le tableau montre ce qui apparaît sur le réseau pour chaque type de liaison.

rpc / littéral
<operation name="method1" style="rpc" ...> <input> <soap:body parts="p1 p2 p3 p4"

use="literal" namespace="(MessageNS)"/> </input> </operation>

sur le réseau :
<soapenv:body... xmlns:mns="(MessageNS)" xmlns:stns="(SchemaTNS)"> <mns:method1> <mns:p1> <stns:a>123</stns:a> <stns:b>bonjour</stns:b> </mns:p1> <mns:p2>123</mns:p2> <mns:p3>

<stns:SimpleElement>

123

</stns:SimpleElement> </mns:p3> <mns:p4> <stns:CompositeElement> <stns:a>123</stns:a> <stns:b>bonjour</stns:b> </stns:CompositeElement> </mns:p4> </mns:method1> </soapenv:body>

document / littéral / type=
<operation name="method1"

style="document" ...> <input> <soap:body parts="p1" use="literal"> </input> </operation>

sur le réseau :

<soapenv:body... xmlns:stns="(SchemaTNS)"> <stns:a>123</stns:a> <stns:b>bonjour</stns:b> </soapenv:body>

rpc / codé
<operation name="method1" style="rpc" ...> <input> <soap:body parts="p1 p2" use="encoded" encoding=

"http://schemas.xmlsoap.org/soap/encoding/" namespace="(MessageNS)"/> </input> </operation>

sur le réseau :
<soapenv:body... xmlns:mns="(MessageNS)"> <mns:method1> <p1 TARGET="_self" class="n" href="#1"/> <p2>123</p2> </mns:method1> <mns:CompositeType id="#1"> <a>123</a> <b>bonjour</b> </mns:CompositeType> </soapenv:body>

document / littéral / élément=
<operation name="method1"

style="document" ...> <input> <soap:body parts="p3 p4"

use="literal"> </input> </operation>

sur le réseau :

<soapenv:body... xmlns:stns="(SchemaTNS)"> <stns:SimpleElement>

123

</stns:SimpleElement> <stns:CompositeElement> <stns:a>123</stns:a> <stns:b>bonjour</stns:b> </stns:CompositeElement> </soapenv:body>

 
document / codé
<operation name="method1"

style="document" ...> <input> <soap:body parts="p1 p2" use="encoded" encoding=

"http://schemas.xmlsoap.org/soap/encoding/" namespace="(MessageNS)"/> </input> </operation>

sur le réseau :
<soapenv:body... xmlns:mns="(MessageNS)"> <mns:CompositeType> <a>123</a> <b>bonjour</b> </mns:CompositeType> <soapenc:int>123</soapenc:int> </soapenv:body>

Éléments <service> et <port>

Un service est un ensemble d'éléments <port>. Chaque élément <port> associe un emplacement à une liaison (<binding>) par paire. S'il y a plusieurs éléments <port> associés au même élément <binding>, les emplacements d'URL supplémentaires peuvent être utilisés comme des alternatives.

Il peut y avoir plusieurs éléments <service> dans un document WSDL. De nombreuses méthodes existent pour autoriser plusieurs éléments <service>. L'une d'elles consiste à regrouper les ports en fonction de la destination de l'URL. Ainsi, je peux rediriger toutes mes demandes d'inventaire en utilisant simplement un autre <service> ; mon programme client continuerait à fonctionner car, dans ce type de service, le regroupement du protocole est indépendant des différents services. Une autre méthode d'utilisation de plusieurs éléments <service> consiste à classer les ports en fonction du protocole sous-jacent. Par exemple, je peux placer tous les ports HTTP dans un <service>, et tous les ports SMTP dans un autre. Mon client peut alors rechercher le <service> qui correspond au protocole qu'il peut traiter.

<service name="FOOService">
 <port name="fooSamplePort" binding="fooSampleBinding">
 <soap:address 
 location="http://carlos:8080/fooService/foo.asp"/>
 </port>
</service>

Dans un document WSDL, l'attribut de nom du <service> distingue les services les uns des autres. Du fait qu'il peut y avoir plusieurs ports dans un service, les ports possèdent eux aussi un attribut de nom.

Résumé

Dans cet article, j'ai décrit les aspects spécifiques à SOAP les plus évidents pour un document WSDL. Il convient d'ajouter que le langage WSDL ne se limite pas à décrire SOAP via HTTP. Le langage WSDL est suffisamment explicite pour décrire SOAP en utilisant HTTP-POST, HTTP-GET, SMTP et autres. Avec le langage WSDL, SOAP est beaucoup plus facile à appréhender, que ce soit pour les développeurs ou pour les utilisateurs. Je pense que le langage WSDL et SOAP vont conduire ensemble à une toute nouvelle classe d'applications utilisant les services Web distribués sur le réseau.

WSDL possède un certain nombre d'éléments XML dans son espace de noms. Le tableau suivant répertorie ces éléments, leurs attributs et leur contenu :

Élément Attribut(s) Contenu (enfants)
<definitions> name
targetNamespace
xmlns (autres espaces de noms)
<types>
<message>
<portType>
<binding>
<service>
<types> (aucun) <xsd:schema>
<message> name <part>
<portType> name <operation>
<binding> name
type
<operation>
<service> name <port>
<part> name
type
(vide)
<operation> name
parameterOrder
<input>
<output>
<fault>
<input> name
message
(vide)
<output> name
message
(vide)
<fault> name

message
(vide)
<port> name
binding
<soap:address>

Dernière mise à jour le lundi 26 novembre 2001

Pour en savoir plus