首页 > 开发 > 综合 > 正文

WSDL文件详解(转贴)中

2024-07-21 02:21:57
字体:
来源:转载
供稿:网友
wsdl 類型與訊息區段中的 xml 結構描述
wsdl 的資料類型,是根據目前 w3c recommendation 的「xml schema: datatypes」(xsd)。此文件共有三種不同的版本 (1999、2000/10、與 2001),若欲指定特定 wsdl 檔案所使用的版本,請在 <definitions> 元素中,將其宣告為命名空間的屬性。方法如下:

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

本文僅以 2001 版為考量。wsdl 標準的擁護者,也大力建議使用 2001 版。

在本節與後續章節中,採用的字首或命名空間速記法如下:

字首 對應的命名空間 說明
soapenc http://schemas.xmlsoap.org/soap/encoding soap 1.1 編碼
wsdl http://schemas.xmlsoap.org/wsdl/soap wsdl 1.1
xsd http://www.w3.org/2001/xmlschema xml schema

xsd 基本類型
下表直接取自 mstk2 文件,列舉了 mstk2 支援的所有 xsd 基本類型。該表說明,位於客戶端與伺服端的 wsdl 讀者,如何在 vb、c++、與 idl 中,將 xsd 類型對應至不同與對等的類型。

xsd (soap) 類型 不同的類型 vb c++ idl 註解
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 轉換時驗證範圍。
date vt_date date date date 時間設為 oo:oo:oo
datetime vt_date date date date
double vt_r8 double double double
duration vt_bstr string bstr bstr 不執行驗證或轉換
entities vt_bstr string bstr bstr 不執行驗證或轉換
entity vt_bstr string bstr bstr 不執行驗證或轉換
float vt_r4 single float float
gday vt_bstr string bstr bstr 不執行驗證或轉換
gmonth vt_bstr string bstr bstr 不執行驗證或轉換
gmonthday vt_bstr string bstr bstr 不執行驗證或轉換
gyear vt_bstr string bstr bstr 不執行驗證或轉換
gyearmonth vt_bstr string bstr bstr 不執行驗證或轉換
id vt_bstr string bstr bstr 不執行驗證或轉換
idref vt_bstr string bstr bstr 不執行驗證或轉換
idrefs vt_bstr string bstr bstr 不執行驗證或轉換
int vt_i4 long long long
integer vt_decimal variant decimal decimal 轉換時驗證範圍。
language vt_bstr string bstr bstr 不執行驗證或轉換
long vt_decimal variant decimal decimal 轉換時驗證範圍。
name vt_bstr string bstr bstr 不執行驗證或轉換
ncname vt_bstr string bstr bstr 不執行驗證或轉換
negativeinteger vt_decimal variant decimal decimal 轉換時驗證範圍。
nmtoken vt_bstr string bstr bstr 不執行驗證或轉換
nmtokens vt_bstr string bstr bstr 不執行驗證或轉換
nonnegativeinteger vt_decimal variant decimal decimal 轉換時驗證範圍。
nonpositiveinteger vt_decimal variant decimal decimal 轉換時驗證範圍。
normalizedstring vt_bstr string bstr bstr
notation vt_bstr string bstr bstr 不執行驗證或轉換
number vt_decimal variant decimal decimal
positiveinteger vt_decimal variant decimal decimal 轉換時驗證範圍。
qname vt_bstr string bstr bstr 不執行驗證或轉換
short vt_i2 integer short short
string vt_bstr string bstr bstr
time vt_date date date date day 設定成 1899 年 12 月 30 日
token vt_bstr string bstr bstr 不執行驗證或轉換
unsignedbyte vt_ui1 byte unsigned char unsigned char
unsignedint vt_decimal variant decimal decimal 轉換時驗證範圍。
unsignedlong vt_decimal variant decimal decimal 轉換時驗證範圍。
unsignedshort vt_ui4 long long long 轉換時驗證範圍。

xsd 定義兩組內建的資料類型:基本類型與衍生類型。若需進一步資訊,可前往 http://www.w3.org/tr/2001/pr-xmlschema-2-20010330,檢視內建類型的階層架構。

複雜類型
xml schema 可定義複雜類型,也就是 c 中的 struct。例如,下列 c struct 的相對定義方式為:

typedef struct {
string firstname;
string lastname;
long ageinyears;
float weightinlbs;
float heightininches;
} person;

若使用 xml schema 可以撰寫成:

<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>

不過,<complextype> 所能表示的,絕不僅止於 struct 的對應而已。除了 <sequence> 之外,它還可以有其它的子元素。若不用 <sequence>,也可以使用 <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>

其意義則是,成員變數 <element> 可以任何順序輸入,且每一項都具有選擇性。這點便與 c struct 的使用方式不同了。

請注意範例中,string (字串)、int (整數)、float (浮點數) 等內建資料類型的使用方式。c 的字串在 xml 中也是字串,且浮點數還是浮點數。但 c 的 long (長整數),在 xml 則是 int (請參考上表)。

在 wsdl 檔案中,types 區段是宣告上述複雜類型的位置。例如,person 類型可以下列方式宣告,並將其用於 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>

在上述的範例中,第一個訊息的名稱是「addperson」,它有個類型為「person」的 <part>。在 types 區段中,類型 person 會被宣告為複雜類型。

起始 mstk2 soapclient 時,若在上述片段使用完整的 wsdl 檔案,它便可成功地剖析該檔案。不過,它還是不能將函數呼叫,傳送至 <addperson>。這是因為 soapclient 本身不知道如何處理複雜類型;它需要自訂的類型對應器 (mapper) 才能處理複雜類型。在 mstk2 文件中有一個範例應用程式,它含有自訂的類型對應器。

另外還有一個方法,可將 <part> 元素,關連至類型宣告。這個方法使用的是元素,而非類型屬性。下個範例會在 types 區段中,先宣告兩個元素 (「person」與「gender」);然後在「addperson」的 <message> 中,再使用元素屬性參照它們。

<?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>

在 types 區段的 gender <element> 中,內嵌著一個匿名的列舉類型,其值可以是「male」或「female」。然後在「addperson」的 <message> 中,再使用元素屬性 (不用類型屬性) 參照該元素。

若欲關連特定類型至 <part>,使用「元素」與「類型」屬性有何不同?若使用「類型」屬性,part 可描述成能採取數種類型 (就像變數一樣);但若使用「元素」屬性,便不能這麼做。請參考下列範例的說明。

<?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>

此範例也說明了副檔名的衍生用法。「femaleperson」與「maleperson」兩者,都是衍生自「person」。它們都各有一個額外的元素:「femaleperson」的「favoritelipstick」以及「maleperson」的「favoriteshavinglotion」。使用 <choice> 的 construct,這兩個衍生類型又可結合成一個複雜類型「maleorfemaleperson」。最後,在「addperson」的 <message> 中,此結合類型又可供「person」的 <part> 參照。而此 <part> 或參數,可以是「femaleperson」或「maleperson」。

陣列
xsd 可提供 <list> construct,以宣告空白所分隔的項目陣列。但是,soap 並不使用 xsd 清單為陣列編碼;而是為陣列定義自己的類型,即「soap-enc:array」。下列範例說明,如何為單一維度的整數陣列,依其法則導出此種類型:

<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>

只要使用導出限制的方式,即可從 soapenc:array 宣告新的複雜類型。接著便可宣告此複雜類型的屬性:arraytype。參照「soapenc:arraytype」實際上即是 arraytype 屬性的宣告,其方式如下:

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

然後,wsdl:arraytype 屬性值,可決定每個陣列成員的類型。陣列項目也可以是複雜類型:

<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>

wsdl 的要求是,陣列的類型名稱必須是,「arrayof」與陣列項目類型的的串連 (concatenation)。也因此,單從名稱即可得知,「arrayofperson」是 person struct 的陣列。在下例中,只要使用 arrayofperson 宣告一個 <message>,即可新增多個 person:

<?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>

<porttype> 與 <operation> 元素
porttype 可在抽象中,定義多種作業。porttype 中的作業元素,可定義呼叫所有 porttype 方法的語法。每個作業元素都會宣告,方法的名稱、參數 (使用 <message> 元素)、類型 (每個 <message> 中所宣告的 <part> 元素)。

在 wsdl 文件中,可有多個 <porttype> 元素。每個 <porttype> 元素,群組化多個相關作業的方式,與 com 介面群組化方法的方式非常類似。

在一個 <operation> 元素中,最多可有一個 <input> 元素、一個 <output> 元素、與一個 <fault> 元素。這三個元素都各有一個名稱與訊息屬性。

在 <input>、<output>、與 <fault> 元素中使用名稱屬性的目的為何?原來是為了,區別具相同名稱 (多載) 的兩項作業。例如,下列兩個 c 函數,即具有相同的名稱,但不同的參數。

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

使用 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>
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表