5. SOAP编码
SOAP编码风格是基于一个简单类型系统,而这个系统是程序语言、数据库和半结构数据中类型系统的公共特性的泛化。一个类型要么是一个简单(可量化的)类型或是一个复合类型,这个复合类型由多个部分组成,每个部分是一个类型。下面会有类型的更为详细的描述。本节定义了一个编序规则,用于可类型化对象图的编序。它在两个级别上操作。首先,给出一个符号上一致化的由该类型系统描述的模式,构造一个XML语法层的模式。其次,提供一个类型系统的模式以及一个与该模式相一致的值的表示方法,构造一个XML实例层的模式。反之,先提供一个符合这些规则XML实例,然后再给出原始的模式、一个原始值表示,也是可以构造的。
在本节中定义的元素和属性所用到的命名空间标识是"http://www.w3.org/2001/06/soap-encoding"。而这些编码的例子中假定所有命名空间声明都是在更高的元素层次上。
在本节中描述的数据模型和编码风格的使用方式是被鼓励的而不是必备的,其他的数据模型和编码也是可以与SOAP联合使用的(参阅 section 4.1.1)。
5.1 使用XML进行类型编码的规则
XML允许非常柔性地编码数据。SOAP只定义了非常有限的编码规则。本节在一个高层次上定义编码规则,而下一节则描述明确类型的编码规则,当有更细节的需求的时候。本节中描述的编码可以与Section 7中描述的RPC调用和响应的映射联合使用。
为了描述编码,以下术语将被使用:
“value”值是一个字符串(string)、一个可量度对象(数字、日期、玫举)的名字、或是数个简单值的组合。所有的值都有明确的类型。
“simple value”简单值是是一个不可分的值,它不包含任意可以命名的部分。简单值的离子可以是特定的字符串、证书或玫举值等。
“compound value”复合值是一个值的关系的聚集。复合值的例子可以是特定的采购定单、存货报表、街道地址等。
在一个复合值中,每一个相关的值都可以用一个角色名来区分,也可以用一个序数来区分,当然也可以同时使用两者。这被称为“accessor”存取标识。复合值的离子包括特定的采购定单、存货报表等。数组也是复合值。它可以被看成是具有多个相同名字的存取标识(accessor)的复合值,例如RDF。
“array”数组是一个复合值,在其成员值之间仅有顺序位置不同。
“struct”结构是一个复合值,在其成员值之间的区分是依靠存取标识(accessor)。同时所有存取标识的名应不同。
“simple type”简单类型是简单值的类。简单类型的例子包括那些类“string”, “integer”,玫举类等。
“compound type”复合类型是复合值的类。复合类型的例子包括采购定单的抽象类型,这些由该类型派生的采购定单具备相同的存取标识(shipTo, totalCost等),当然他们有不同的值(也许对某些值还有约束)。
在一个复合类型中,一个存取标识在本符合类型中是唯一的,如果它和其他复合类型中的某个存取标识无法相区别,则该存取标识名加上复合类型的名字才能成为唯一标识,这个名称为"局部名"。无论该名是直接或间接基于一个URI,如果该存取标识不用加类型名约束就已经是唯一的,那该名就成为"全局名"。
值表的编序的模式中所给出的信息,是有可能能决定一些值只能关联一个存取标识的简单实例。对于其他可能的情况,则无法下这个断言。一个值被称为”single-reference”单引用,如果只有一个存取标识能够引用它。如果能被多个引用,无论是事实上还是潜在可能,那就是”multi-reference”多引用。注意有可能在一模式中有一个确定的值是单引用而其他则是多引用。
在句法上,一个元素可以是"独立的"或"嵌入的"。一个独立的元素是作为编序中一个顶级元素出现。而其他则是嵌入元素。
尽管使用xsi:type属性可以令值的表示为自描述的,也就是说即包含值的结构也包含值的类型,但编序规则允许值的类型可以仅仅引用模式(Schema)中的类型定义。而这些模式可以使用“XML Schema Part 1: Structures”[10]和“XML Schema Part 2: Datatypes”[11]中定义的规范来描述,当然也可以使用其他的模式定义来定义。注意尽管这样,但许多模式定义只支持结构(struct)和数组(array)类型,而编序规则则有可能要尝试使用结构(struct)和数组(array)类型之外的复合类型。
编序规则如下:
所有的值都应当表现为元素的内容(content)。一个多引用的值必须被表示为一个独立元素的内容。而一个单引用的值应该不如此(不过也可以如此)。
对每个包含一个值的元素,值的类型表示必须满足以下至少一个条件:(a) 包含该值的元素实例包含一个xsi:type属性,(b) 包含该值的元素实例包含在一个具备enc: arrayType属性的元素中(可能是被设置成default的),(c) 该元素的名带有一个类型的明确关联,而该类型由一个模式来决定。
一个简单值应被表示为字符数据(character data),也就是说,没有任何子元素。每一个简单值必须有一个类型,该类型要么是在XML Schema规范的DataTypes部分[11]中被罗列,要么它的源类型应当在该部分中被罗列(可参阅 section 5.2)。
一个复合值应当被编码为一个元素序列,其中每一个存取标识由一个嵌入元素来表示,他们的名是一一对应的。若存取标识的名在包含它的型中是局部的,则它有一个未修饰的元素名,而其他则应有完全修饰的名(可参阅 section 5.4)。
一个多引用的简单或复合值应当被编码为一个独立元素,该独立元素应包含一个局部的带有非限制名的“id”属性,该属性的类型为XML规范[7]中定义的ID类型。对该值的每一个存取标识是一个空元素,该空元素有一个局部的未修饰的属性“href”,该属性类型是XML Schema规范[11]中定义的“uri-reference”类型,“href”属性的值是一个引用该对应独立元素的URI片段标识。
字串和字节数组被表示为多引用简单类型,不过特别的规则也允许它们在通常情况下更有效地表示(可参阅 section 5.2.1以及section 5.2.3)。一个字串或字节数组的存取标识可以有一个在XML规范[7]中定义的名为”id”的ID类型的属性。如果这样的话,所有其他对该同一值的存取标识可以被编码为一个空元素,该空元素应包含一个局部的带有非限制名的“href”属性,该属性的类型为XML Schema规范[11]中定义的“uri-reference”类型,“href”属性的值是一个引用该对应独立元素的URI片段标识。
对一个值编码多个引用是允许的,看上去这些引用好象是引用了多个不同的值,但仅当从上下文中可得到该XML 实例的含义是未改变的的结论。
数组是复合值(可参阅 section 5.4.2)。SOAP数组被定义为类型是“enc:Array”或类型是源于“enc:Array”。
SOAP数组有一或多维,而它的成员由顺序位置区分。一个数组的值被表示为一序列反映该数组的元素,这些成员按序数从小到大顺序出现。对于多维数组,则元素维按从右到左顺序变化。没一个成员元素都被命名为一个独立元素(参阅 rule 2)。
SOAP数组可以是单引用值,也可以是多引用值,从而可以被表示为一个嵌入元素或一个独立元素。
SOAP数组必须包含一个“enc:arrayType”属性,其中定义的包含元素的值的类型与维数一起描述了该数组。”enc:arrayType”属性的值定义如下:
arrayTypeValue
=
atype asize
atype
=
QName *( rank )
rank
=
"[" *( "," ) "]"
asize
=
"[" #length "]"
length
=
1*DIGIT
“atype”结构是数组所包含的元素的类型的名,首先它包含一个QName表示,QName应在XML Schema元素声明中的“type”属性中出现,QName是一个型约束(意味着所有其包含的元素都应宣称与该指明的类型相一致,也就是说,在enc:arrayType中引用的类型必须是所有数组元素的类型或超类型)。对于那些数组的数组或是“jagged arrays”,使用rank结构来表示数组的元素是一个数组,同时该数组的具体类型将在下层具体成员数组的定义时数值实例化,rank中出现零个、一个到多个逗号,表明该成员变量是一维、二维或多维数组。对于多维数组,维数定义为一个由“,”分隔的维数序列,每个维数的记数基数为1。
“asize”结构包含一个由逗号分隔的由零个、一个或多个整数组成的序列指明的数组的每个维的长度。一个由零个整数组成的序列表明对数组打下并没有特别限制,不过具体的大小将由下层具体的成员来决定。
例如,一个有5个成员的数组,成员类型为integer数组,它的arrayTypeValue的值就应当是 “int[][5]”。其中,atype的值是“int[]”,asize的值是“[5]”。类似地,一个有3个成员的数组,成员类型为integer二维数组,它的arrayTypeValue的值就应当是 “int[,][3]”。其中,atype的值是“int[,]”,asize的值是“[3]”。
SOAP数组成员可以包含一个“enc:offset”属性来指明该成员在其装载的数组中的偏移量。这也可以用于指明在一个部分描述的数组中成员的偏移(参阅 section 5.4.2.1)。类似的,SOAP数组成员可以包含一个“enc:position”属性来指明该成员在其装载的数组中的位置。这也可以用于指明在一个稀疏描述的数组中成员的位置(参阅 section 5.4.2.2)。“enc:offset”和“enc:position”属性的值定义为:
arrayPoint
=
"[" #length "]"
他们的基数都是0。
NULL值和默认值可以在存取标识元素中省略。NULL值可以在一个存取标识元素中使用一个值为1的属性xsi:null来指明,或者可以是其他依赖于应用程序的属性和值。
注意rule 2允许独立元素和数组中成员元素对于包含的类型可以有不同的名。
5.2 简单类型
对于简单类型,SOAP采用了在“XML Schema Part 2: Datatypes”[11]的“Build-in datatypes”节中定义的所有类型,包括值和词汇空间(lexical spaces)。例子包括:
Type
Example
int
58502
float
314159265358979E+1
negativeInteger
-32768
string
Louis "Satchmo" Armstrong
在XML Schema规范中声明的数据类型可以直接在元素模式中使用。而源于这些类型的类型也可以被使用。下面是一个模式片段和相应类型元素数据的例子:
Example 7
<!-- schema document -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="age" type="xs:int" />
<xs:element name="height" type="xs:float" />
<xs:element name="displacement" type="xs:negativeInteger" />
<xs:element name="color" >
<xs:simpleType base="xsd:string">
<xs:restriction base="xs:string" >
<xs:enumeration value="Green"/>
<xs:enumeration value="Blue"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
Schema with simple types
以下是一些合法的元素实例:
Example 8
<!-- Example instance elements -->
<age>45</age>
<height>5.9</height>
<displacement>-450</displacement>
<color>Blue</color>
Message fragment corresponding to the schema in Example 7
无论简单值类型是在“XML Schema Part 2: Datatypes”规范[11]中定义,还是基于XML Schema规范所提供的类型定义机制,都必须被编码为元素的内容。
如果一个简单值被编码为一个独立元素或一个异构数组的元素,这就很方便有一个对应于数据类型的元素声明。因为“XML Schema Part 2: Datatypes”规范[11]中包含了类型定义,但没有包含对应元素的声明,而enc模式和命名空间为每个简单数据类型声明了一个元素。这些是可以被使用的。
Example 9
<enc:int xmlns:enc="http://www.w3.org/2001/06/soap-encoding" id="int1">45</enc:int>
5.2.1 字符串
“string”数据类型在“XML Schema Part 2: Datatypes”[11]中被定义。值得注意的是在许多数据库或编程语言中,“string”类型并不是一致的,在某些特别的语言中,可能只允许一些字符能出现在“string”中。(这些值可能需要表示为xsd:string之外的一些数据类型)
一个字串可以被编码为一个单引用或多引用值。
包含string值的元素可以有一个“id”属性。额外的存取标识元素可以有匹配它的“href”属性。
例如,如果有两个对同一string的存取标识出现,则可以表现为:
Example 10
<greeting id="String-0">Hello</greeting>
<salutation href="#String-0"/>
Two accessors for the same string
无论如何,事实上对一个string(或者是string的子类型)的实例加以两个引用与将他们编码成两个单引用值并没有本质的区别:
Example 11
<greeting>Hello</greeting>
<salutation>Hello</salutation>
Two accessors for the same string
对于这些例子的模式描述可能是:
Example 12
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding" >
<xs:import namespace="http://www.w3.org/2001/06/soap-encoding" />
<xs:element name="greeting" type="enc:string" />
<xs:element name="salutation" type="enc:string" />
</xs:schema>
Schema for Example 11
(在这个例子中,用于描述元素类型的enc:string类型是一个方便的方法,来描述一个元素的类型是“xsd:string”,并且它可以附带“id” 和“href”属性。可以参阅SOAP Encoding模式来得到确切的定义。模式也可以使用这些SOAP Encoding模式中的声明,但不是必须的。)
5.2.2 枚举
“XML Schema Part 2: Datatypes”规范[11]定义了一种称为“玫举(enumeration)”的机制。SOAP数据模型直接采用了这个机制。可是,由于编程语言及其他语言在定义玫举上存在着一些细微的差别,因此我们在这里描述了更详细的概念,并描述了如何将一个成为玫举列表成员的值进行编码。具体的,它编码为该值的名。
在概念上,“玫举”表示了一组不同的名。一个具体的玫举是一个符合基本类型的不同值的具体列表。例如,颜色名(“Green”, “Blue”, “Brown”)的集合可以被定义为一个基于内置string类型的玫举, 值(“1”, “3”, “5”)则可能是一个基于integer的玫举,等等。“XML Schema Part 2: Datatypes”规范[11]支持除boolean外所有简单类型的玫举。“XML Schema Part 2: Structures”规范[10]语言可以用于定义玫举类型。如果一个模式是从另一种符号体系生成过来而没有具体的基本类型可应用,那么就使用“string”。在下面的模式例子“EyeColor”被定义为一个string的玫举,其可能的值包括“Green”、“Blue”、“Brown”,同时实例数据也对应地给出了。
Example 13
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.org/2001/06/samples"
targetNamespace="http://example.org/2001/06/samples" >
<xs:element name="EyeColor" type="tns:EyeColor" />
<xs:simpleType name="EyeColor" >
<xs:restriction base="xs:string" >
<xs:enumeration value="Green" />
<xs:enumeration value="Blue" />
<xs:enumeration value="Brown" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
Schema with enumeration
Example 14
<p:EyeColor xmlns:p="http://example.org/2001/06/samples" >Brown</p:EyeColor>
Message fragment corresponding to the schema in Example 13
5.2.3 字节数组
一个Byte数组可以编码为单引用或多引用值。Byte数组的编码规则与string是类似的。
特别的,包含Byte数组值的元素可以有一个“id”属性。额外的存取标识元素可以有一个用于匹配的“href”属性。
对一个不透明的Byte数组的推荐表示是使用在XML Schema规范[10][11]中定义的“base64”编码方式,具体编码算法是在RFC 2045[13]中定义。不过,MIME中base64编码数据的数据行长度限制在SOAP中将不存在。SOAP中应使用“enc:base64”子类型来定义base64编码。
Example 15
<picture xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xsi:type="enc:base64" >
aG93IG5vDyBicm73biBjb3cNCg==
</picture>
Image with base64 encoding
5.3 多态存取标识
许多语言允许存取标识可以多态地访问数个类型的值,在运行时刻每个类型都是可使用的。一个多态存取标识实例必须包含一个“xsi:type”属性以描述类型的实际值。
例如,一个名为“cost”带有类型为“xsd:float”的值的多态存取标识可以编码为:
Example 16
<cost xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xsi:type="xs:float">29.95</cost>
Polymorphic accessor
与之相对的是一个值类型不变的cost存取标识。
Example 17
<cost>29.95</cost>
Accessor whose value type is invariant
5.4 复合类型
SOAP依照在程序语言中常常看见的以下结构模式来定义复合类型:
Struct
“struct”是一个复合类型值,其成员的存取标识名是相互区别的唯一标志,应彼此各不相同。
Array
“array”是一个复合类型值,其成员的顺序位置是相互区别的唯一标志。
SOAP也允许数据的编序即不是Struct也不是Array,例如在Directed-Labeled-Graph数据模型中单个数据结点有很多不同的存取标识,其中有些会出现多次。SOAP遍序并不需要下层的数据模型要区别存取标识的次序区别,但如果有这种次序存在的话,那么存取标识必须按照该次序编码。
5.4.1 复合值及对值的引用
复合值的成员被编码为存取标识元素。存取标识由他们的名字来相区别(例如在struct里面),而元素名就是存取标识名。存取标识名是局部的,作用域是包含他们的类型中,具备一个未修饰的元素名,而其他则有完全修饰名。
下面是一个“Book”结构的例子:
Example 18
<e:Book xmlns:e="http://example.org/2001/06/books" >
<author>Henry Ford</author>
<preface>Prefactory text</preface>
<intro>This is a book.</intro>
</e:Book>
Book structure
下面则是一个描述该结构的模式片段:
Example 19
<xs:element name="Book"
xmlns:xs='http://www.w3.org/2001/XMLSchema' >
<xs:complexType>
<xs:sequence>
<xs:element name="author" type="xs:string" />
<xs:element name="preface" type="xs:string" />
<xs:element name="intro" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
Schema for Example 18
下面是一个即包含简单类型成员也包含复合类型成员的类型的例子。它显示了两层的引用。注意“Author”存取标识元素的“href”属性一个对匹配“id”值对应的值的引用。“Address”中的情况也是类似的。
Example 20
<e:Book xmlns:e="http://example.org/2001/06/books" >
<title>My Life and Work</title>
<author href="#Person-1"/>
</e:Book>
<e:Person xmlns:e="http://example.org/2001/06/books"
id="Person-1" >
<name>Henry Ford</name>
<address href="#Address-2"/>
</e:Person>
<e:Address xmlns:e="http://example.org/2001/06/books"
id="Address-2" >
<email>mailto:henryford@hotmail.com</email>
<web>http://www.henryford.com</web>
</e:Address>
Book with muli-reference addresses
当“Person”和“Address”的值是需要多引用的时候,上述描述是合适的。如果使用单引用来描述,则应该是嵌入的,如下:
Example 21
<e:Book xmlns:e="http://example.org/2001/06/books" >
<title>My Life and Work</title>
<author>
<name>Henry Ford</name>
<address>
<email>mailto:henryford@hotmail.com</email>
<web>http://www.henryford.com</web>
</address>
</author>
</e:Book>
Book with single-reference addresses
如果这里存在着一个限制:在一个给出的实例中不允许有两个人有同样的地址,地址可以是一个街道地址(Street-address),也可以是一个电子地址(Electronic-address)。一本有两个作者的书可以编码为:
Example 22
<e:Book xmlns:e="http://example.org/2001/06/books" >
<title>My Life and Work</title>
<firstauthor href="#Person-1"/>
<secondauthor href="#Person-2"/>
</e:Book>
<e:Person xmlns:e="http://example.org/2001/06/books"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
id="Person-1" >
<name>Henry Ford</name>
<address xsi:type="e:ElectronicAddressType">
<email>mailto:henryford@hotmail.com</email>
<web>http://www.henryford.com</web>
</address>
</e:Person>
<e:Person xmlns:e="http://example.org/2001/06/books"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
id="Person-2">
<name>Samuel Crowther</name>
<address xsi:type="e:StreetAddressType">
<street>Martin Luther King Rd</street>
<city>Raleigh</city>
<state>North Carolina</state>
</address>
</e:Person>
Book with two authors having different addresses
编序也可以包含一些不在同一资源中的值的引用:
Example 23
<e:Book xmlns:e="http://example.org/2001/06/books" >
<title>Paradise Lost</title>
<firstAuthor href="http://www.dartmouth.edu/~milton/" />
</e:Book>
Book with external references
同时下面是一个对上面结构的模式描述片段:
Example 24
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://example.org/2001/06/books"
targetNamespace="http://example.org/2001/06/books" >
<xs:element name="Book" type="tns:BookType" />
<xs:complexType name="BookType" >
<xs:annotation>
<xs:documentation>
<info>
Either the following group must occur or else the
href attribute must appear, but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:sequence minOccurs="0" maxOccurs="1" >
<xs:element name="title" type="xs:string" />
<xs:element name="firstAuthor" type="tns:PersonType" />
<xs:element name="secondAuthor" type="tns:PersonType" />
</xs:sequence>
<xs:attribute name="href" type="xs:anyURI" />
<xs:attribute name="id" type="xs:ID" />
<xs:anyAttribute namespace="##other" />
</xs:complexType>
<xs:element name="Person" type="tns:PersonType" />
<xs:complexType name="PersonType" >
<xs:annotation>
<xs:documentation>
<info>
Either the following group must occur or else the
href attribute must appear, but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:sequence minOccurs="0" maxOccurs="1" >
<xs:element name="name" type="xs:string" />
<xs:element name="address" type="tns:AddressType" />
</xs:sequence>
<xs:attribute name="href" type="xs:anyURI" />
<xs:attribute name="id" type="xs:ID" />
<xs:anyAttribute namespace="##other" />
</xs:complexType>
<xs:element name="Address" base="tns:AddressType" />
<xs:complexType name="AddressType" abstract="true" >
<xs:annotation>
<xs:documentation>
<info>
Either one of the following sequences must occur or
else the href attribute must appear, but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:choice>
<xs:sequence minOccurs="0" maxOccurs="1" >
<xs:element name="email" type="xs:string" />
<xs:element name="web" type="xs:anyURI" />
</xs:sequence>
<xs:sequence minOccurs='0' maxOccurs='1' >
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="href" type="xs:anyURI"/>
<xs:attribute name="id" type="xs:ID"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="StreetAddressType">
<xs:annotation>
<xs:documentation>
<info>
Either the second sequence in the following group
must occur or else the href attribute must appear,
but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:complexContent>
<xs:restriction base="tns:AddressType" >
<xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="0" >
<xs:element name="email" type="xs:string" />
<xs:element name="web" type="xs:anyURI" />
</xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string"/>
</xs:sequence>
</xs:sequence>
<xs:attribute name="href" type="xs:anyURI"/>
<xs:attribute name="id" type="xs:ID"/>
<xs:anyAttribute namespace="##other"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="ElectronicAddressType">
<xs:annotation>
<xs:documentation>
<info>
Either the first sequence in the following group
must occur or else the href attribute must appear,
but not both.
</info>
</xs:documentation>
</xs:annotation>
<xs:complexContent>
<xs:restriction base="tns:AddressType" >
<xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element name="email" type="xs:string" />
<xs:element name="web" type="xs:anyURI" />
</xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="0">
<xs:element name="street" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="state" type="xs:string"/>
</xs:sequence>
</xs:sequence>
<xs:attribute name="href" type="xs:anyURI"/>
<xs:attribute name="id" type="xs:ID"/>
<xs:anyAttribute namespace="##other"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Schema for example 22
5.4.2 数组
SOAP数组被定义为类型为“enc:Array”或类型源于“enc:Array”(可参阅 rule 8)。这种类型源于"enc:Array"的类型必须遵从"enc:Array"的限制,同时它可用于表示以下情况的类型定义,譬如整型数的数组或是一些用户自定义的枚举类型的数组等。数组被表示为对包含其的元素的名无特殊约束的元素值(就象值一般不会约束包含元素的名)。组成数组的元素可以是任意类型,包括嵌套的数组。
数组值的表示是一个该数组组成元素的一个有序序列。作为一个数组的值,元素名对于区分存取标识并非重要。元素可以有任意的名。实际上,这些元素的命名将按照模式中声明的建议,或由他们的类型所决定。就象在复合类型中通常情况下,如果数组中条目的值是单引用值,则该条目将包含它的值。否则,条目通过“href”属性引用它的值。
下面是一个模式的片段以及一个包含integer成员的数组:
Example 25
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding" >
<xs:import namespace="http://www.w3.org/2001/06/soap-encoding" />
<xs:element name="myFavoriteNumbers" type="enc:Array" />
</xs:schema>
Schema declaring an array of integers
Example 26
<myFavoriteNumbers xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xs:int[2]" >
<number>3</number>
<number>4</number>
</myFavoriteNumbers>
Array conforming to the schema in Example 25
在这个例子中,“myFavoriteNumber”数组包含了几个成员,每个成员的值的类型都是xs:int。而类型是由enc:arrayType属性决定的。注意enc:Array的类型允许不严格的未修饰的元素名。这些名只传输了非类型的信息,因此在具体使用的时候,要么有一个xsi:type属性,要么包含它的元素要包含一个enc:arrayType属性。自然地,源于enc:Array的类型可以声明带类型信息的局部元素。
就象先前指出的,enc模式包含了一些元素名的声明,而这些名是对应于“XML Schema Part 2: Datatypes”规范[11]中的每个简单类型的。这也包含一个“Array”的声明。使用这些定义,我们也许可以将显现先前的描述改写为:
Example 27
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
enc:ArrayType="xs:int[2]" >
<enc:int>3</enc:int>
<enc:int>4</enc:int>
</enc:Array>
Using the enc:Array element
数组可以包含任意指定arrayType的子类型的实例。也就是说,成员的类型可以是任何描述在arrayType属性中类型的可替代类型,这将依照于在模式中表示的可替代规则。因此,例如,一个整数数组可以包含任何源于integer的类型的值(例如 “int”或任何用户定义的源于integer的类型)。类似的,一个“address”数组可以包含一个严格的或扩展的类型,比如“internationalAddress”。因为提供的enc:Array类型允许包含任何类型或类型混合的成员,除非有对arrayType属性使用的特别限制。
成员元素类型在实例中可以使用xsi:type来描述,或则是在成员元素模式中声明,就象在下面两个数组中分别演示的那样:
Example 28
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
enc:arrayType="xs:anyType[4]">
<thing xsi:type="xs:int">12345</thing>
<thing xsi:type="xs:decimal">6.789</thing>
<thing xsi:type="xs:string">
Of Mans First Disobedience, and the Fruit
Of that Forbidden Tree, whose mortal tast
Brought Death into the World, and all our woe,
</thing>
<thing xsi:type="xs:anyURI">
http://www.dartmouth.edu/~milton/reading_room/
</thing>
</enc:Array>
Array with elements of varying types
Example 29
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xs:anyType[4]" >
<enc:int>12345</enc:int>
<enc:decimal>6.789</enc:decimal>
<enc:string>
Of Mans First Disobedience, and the Fruit
Of that Forbidden Tree, whose mortal tast
Brought Death into the World, and all our woe,
</enc:string>
<enc:anyURI>
http://www.dartmouth.edu/~milton/reading_room/
</enc:anyURI >
</enc:Array>
Array with elements of varying types
数组值可以是结构或其他复合值。例如一个“xyz:Order”结构的数组:
Example 30
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xyz="http://example.org/2001/06/Orders"
enc:arrayType="xyz:Order[2]">
<Order>
<Product>Apple</Product>
<Price>1.56</Price>
</Order>
<Order>
<Product>Peach</Product>
<Price>1.48</Price>
</Order>
</enc:Array>
Arrays containing structs and other compound values
数组也可以有一些成员值是数组。下面是一个有两个数组的数组的例子,而那两个数组都是string数组:
Example 31
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xs:string[][2]" >
<item href="#array-1"/>
<item href="#array-2"/>
</enc:Array>
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
id="array-1"
enc:arrayType="xs:string[2]">
<item>r1c1</item>
<item>r1c2</item>
<item>r1c3</item>
</enc:Array>
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
id="array-2"
enc:arrayType="xs:string[2]">
<item>r2c1</item>
<item>r2c2</item>
</enc:Array>
Array containing other arrays
包含一个数组值的元素并不需要一定被命名为“enc:Array”。它可以有任意的名,而提供的类型则要么是enc:Array,要么是受源于enc:Array的限制。例如,下面是一个模式片段以及与之一致的一个实例数组:
Example 32
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:tns="http://example.org/2001/06/numbers"
targetNamespace="http://example.org/2001/06/numbers" >
<xs:simpleType name="phoneNumberType" >
<xs:restriction base="xs:string" />
</xs:simpleType>
<xs:element name="ArrayOfPhoneNumbers" type="tns:ArrayOfPhoneNumbersType" />
<xs:complexType name="ArrayOfPhoneNumbersType" >
<xs:complexContent>
<xs:restriction base="enc:Array" >
<xs:sequence>
<xs:element name="phoneNumber" type="tns:phoneNumberType" maxOccurs="unbounded" />
</xs:sequence>
<xs:attributeGroup ref="enc:arrayAttributes" />
<xs:attributeGroup ref="enc:commonAttributes" />
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Schema for an array
Example 33
<abc:ArrayOfPhoneNumbers xmlns:abc="http://example.org/2001/06/numbers"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="abc:phoneNumberType[2]" >
<phoneNumber>206-555-1212</phoneNumber>
<phoneNumber>1-888-123-4567</phoneNumber>
</abc:ArrayOfPhoneNumbers>
Array conforming to the schema in Example 32
数组可以是多维的。在这种情况下,就会有多个描述维数大小的值出现在arrayType属性的asize部分:
Example 34
<enc:Array xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xs:string[2,3]" >
<item>r1c1</item>
<item>r1c2</item>
<item>r1c3</item>
<item>r2c1</item>
<item>r2c2</item>
<item>r2c3</item>
</enc:Array>
Multi-dimensonal array
上述例子中显示了一个数组如何被编码为独立元素,数组值可以以嵌套方式出现并且如果他们是单引用的话,应该使用这种方式。
下面是一个模式片段的例子以及符合该模式的一个嵌套在“Person”结构中的电话号码数组,该数组可以从存取标识“phone-numbers”访问:
Example 34
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:tns="http://example.org/2001/06/numbers"
targetNamespace="http://example.org/2001/06/numbers" >
<xs:import namespace="http://www.w3.org/2001/06/soap-encoding" />
<xs:simpleType name="phoneNumberType" >
<xs:restriction base="xs:string" />
</xs:simpleType>
<xs:element name="ArrayOfPhoneNumbers" type="tns:ArrayOfPhoneNumbersType" />
<xs:complexType name="ArrayOfPhoneNumbersType" >
<xs:complexContent>
<xs:restriction base="enc:Array" >
<xs:sequence>
<xs:element name="phoneNumber" type="tns:phoneNumberType" maxOccurs="unbounded" />
</xs:sequence>
<xs:attributeGroup ref="enc:arrayAttributes" />
<xs:attributeGroup ref="enc:commonAttributes" />
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:element name="Person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="phoneNumbers" type="tns:ArrayOfPhoneNumbersType" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Schema fragment for array of phone numbers embedded in a struct
Example 35
<def:Person xmlns:def="http://example.org/2001/06/numbers"
xmlns:enc="http://www.w3.org/2001/06/soap-encoding" >
<name>John Hancock</name>
<phoneNumbers enc:arrayType="def:phoneNumber[2]">
<phoneNumber>206-555-1212</phoneNumber>
<phoneNumber>1-888-123-4567</phoneNumber>
</phoneNumbers>
</def:Person>
Array of phone numbers embedded in a struct conforming to the schema in Example 34
下面是单引用数组值的另一个例子,数组值被编码为嵌入元素,这些元素都包含作为存取标识的元素名:
Example 36
<xyz:PurchaseOrder xmlns:xyz="http://example.org/2001/06/Orders" >
<CustomerName>Henry Ford</CustomerName>
<ShipTo>
<Street>5th Ave</Street>
<City>New York</City>
<State>NY</State>
<Zip>10010</Zip>
</ShipTo>
<PurchaseLineItems xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
enc:arrayType="xyz:Order[2]">
<Order>
<Product>Apple</Product>
<Price>1.56</Price>
</Order>
<Order>
<Product>Peach</Product>
<Price>1.48</Price>
</Order>
</PurchaseLineItems>
</xyz:PurchaseOrder>
Single-reference array encoded as en embedded element
5.4.2.1 部分传输数组
SOAP提供对部分传递数组的支持,这就象在一些上下文[12]中的“可变长”数组。一个部分传递数组应使用“enc:offset”属性标识,该属性的记数是以第一元素的位移为0开始的。如果省略该属性,则位移默认是0。
下面是一个大小为5的数组,同时在传递的时候仅传递第三和第四个元素:
Example 37
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
enc:arrayType="xs:string[6]"
enc:offset="[3]" >
<item>The fourth element</item>
<item>The fifth element</item>
</enc:Array>
Array of size five that transmits only the third and fourth element
5.4.2.2 稀疏数组
SOAP提供对稀疏数组的支持。每一个表示成员值的元素包含一个“enc:position”属性来表明它处于数组的位置。下面是一个二维字串数组的稀疏数组的例子。他的大小是4,但仅有位置2被使用:
Example 38
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
enc:arrayType="xs:string[,][4]" >
<enc:Array href="#array-1" enc:position="[2]" />
</enc:Array>
<enc:Array id="array-1"
enc:arrayType="xs:string[10,10]" >
<item enc:position="[2,2]">Third row, third col</item>
<item enc:position="[7,2]">Eighth row, third col</item>
</enc:Array>
Sparse array
如果在上述数组中对array-1仅有一个引用,那上述例子可以被编码为:
Example 39
<enc:Array xmlns:enc="http://www.w3.org/2001/06/soap-encoding"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
enc:arrayType="xs:string[,][4]" >
<enc:Array enc:position="[2]" enc:arrayType="xs:string[10,10]" >
<item enc:position="[2,2]">Third row, third col</item>
<item enc:position="[7,2]">Eighth row, third col</item>
</enc:Array>
</enc:Array>
Another sparse array
5.4.3 通用复合类型
上面引用到的编码规则并不限于那些预先知道存取标识的情形。如果存取标识名仅当在编码过程中由值的出现才能决定的时候,同样的规则也可以应用,也就是一个存取标识被编码为同名的元素,并且该存取标识要么包含要么引用它的值。包含那些类型不能预先决定的值的存取标识必须包含一个合适的xsi:type属性来给出值的类型。
类似的,引用的规则对于包含一些混合的存取标识的复合类型的编序而言已经足够了,这些存取标识有的是以名来区分,有的是以名和位置来区分 (也就是说,有些存取标识会重复出现) 。这并不一定需要有包含这一类型的模式存在,但是如果一个类型模型模式没有该类型时,那么一个对应的XML句法模式和实例就应该被生成。
Example 40
<xyz:PurchaseOrder xmlns:xyz="http://example.org/2001/06/Orders" >
<CustomerName>Henry Ford</CustomerName>
<ShipTo>
<Street>5th Ave</Street>
<City>New York</City>
<State>NY</State>
<Zip>10010</Zip>
</ShipTo>
<PurchaseLineItems>
<Order>
<Product>Apple</Product>
<Price>1.56</Price>
</Order>
<Order>
<Product>Peach</Product>
<Price>1.48</Price>
</Order>
</PurchaseLineItems>
</xyz:PurchaseOrder>
Generic compound types
类似的,将一个复合类型值编序为类似数组结构的是合法的,但这不是enc:Array类型或其子类型。例如:
Example 41
<PurchaseLineItems>
<Order>
<Product>Apple</Product>
<Price>1.56</Price>
</Order>
<Order>
<Product>Peach</Product>
<Price>1.48</Price>
</Order>
</PurchaseLineItems>
Compound value
5.5 默认值
一个省略格式的存取标识元素以为着有一个默认值或是尚不知道它的值。而该细节是基于存取标识、方法和上下文的。例如一个省略格式的存取标识典型地是表示一个多态存取标识的Null值(Null依赖存取标识的确切含义)。同样地,一个省略格式的Boolean存取标识典型地就意味着是一个False值或值未知,同时一个省略格式的数值存取标识典型地意味着它的值是0或值未知。
5.6 SOAP root属性
SOAP root属性可以被用来标注编序的根,当然他并不是对象图真正的根,所以对象图是可以解序的。该属性可以赋予“0”和“1”这两个值的任意一个。一个对象图的真正的根一般就有值“1”。那些非真正根的编序根也可以被标注为赋予值为“1”的编序根。一个元素也可以被明确地标注为赋予值为“0”的非编序根。
SOAP根属性可以出现在SOAP Header和SOAP Body元素中的任何子元素里,该属性并没有一个默认值。