当前位置导航:炫浪网>>网络学院>>编程开发>>JAVA教程>>JAVA网络编程

理解XML Schema: XML Schema 初步

    本文章系列是XML Schema的一个从入门到进阶的基本教程。内容主要翻译整理了W3C关于XML Schema的入门级规范:XML Schema Part 0: Primer( http://www.w3.org/TR/xmlschema-0/),同时译者添加了一些个人的编注,并重新整理安排了章节。奉献给大家,旨在让更多的读者来了解,熟悉XML Schema. XML Schema是W3C的推荐标准,于2001年5月正式发布,经过数年的大规模讨论和开发,终于最终奠定下来,使得XML建模有了一个国际标准。XML Schema一确定下来,立刻成为全球公认得首选XML环境下的建模工具,已经基本取代了DTD在XML刚刚成为W3C推荐标准时的地位。由于XML是SGML的一个子集,因此它也继承了SGML世界中用于建模的DTD,当时使用DTD的好处是可以利用大量的在SGML世界中现有的DTD工具,使得开发应用代价维持在一个相对较低的水平。然而,DTD有着不少缺陷:1)DTD是基于正则表达式的,描述能力有限;2) DTD没有数据类型的支持,在大多数应用环境下能力不足;3) DTD的约束定义能力不足,无法对XML实例文档作出更细致的语义限制;4) DTD的结构不够结构化,重用的代价相对较高;5)DTD并非使用XML作为描述手段,而DTD的构建和访问并没有标准的编程接口,无法使用标准的编程方式进行DTD维护。而XML Schema正是针对这些DTD的缺点而设计的,XML Schema是完全使用XML作为描述手段,具有很强的描述能力、扩展能力和处理维护能力。

    XML Schema的主要目的是用来定义一类XML文档(一个XML Application)。因此模式的"实例文档"形式常常用来描述一个与特定XML Schema相一致的XML文档。事实上,文档实例和Schema文档都不是必须要以文档的形式存在,他们可以存在以于应用之间传递的字节流的形式存在,或者作为一个数据库记录或者作为XML的"信息项"的集合而存在。然而为了简化入门,我们总是把实例和模式看作文档或者文件,认为它们总以文档实例或是模式文档的形式存在。让我们开始考虑一个在文件po.xml中的实例文档。它描述了一个由家庭产品采购和支付应用生成的购买订单。

po.xml,购买订单的XML实例文档

<?xml version="1.0"?>
<purchaseOrder orderDate="1999-10-20">
    <shipTo country="US">
        <name>Alice Smith</name>
        <street>123 Maple Street</street>
        <city>Mill Valley</city>
        <state>CA</state>
        <zip>90952</zip>
    </shipTo>
    <billTo country="US">
        <name>Robert Smith</name>
        <street>8 Oak Avenue</street>
        <city>Old Town</city>
        <state>PA</state>
        <zip>95819</zip>
    </billTo>
    <comment>Hurry, my lawn is going wild!</comment>
    <items>
        <item partNum="872-AA">
            <productName>Lawnmower</productName>
            <quantity>1</quantity>
            <USPrice>148.95</USPrice>
            <comment>Confirm this is electric</comment>
        </item>
        <item partNum="926-AA">
            <productName>Baby Monitor</productName>
            <quantity>1</quantity>
            <USPrice>39.98</USPrice>
            <shipDate>1999-05-21</shipDate>
        </item>
    </items>
</purchaseOrder>
 
    购买订单由一个主元素purchaseOrder和子元素shipTo、billTo、comment和items组成。这些子元素(除了comment)也依次包括其他子元素等等。直到一个像USPrice这样的子元素,它包含的是一个数字而不是任何子元素。元素如果包含子元素或者是带有属性则被称为复合类型;反之元素如果仅仅包含数字、字符串或者其他数据等,但不包含任何子元素则称为简单类型。

    在实例文档中复合类型和一些简单类型是在购买定单的模式文档中定义。而其他一些标准的简单类型则是作为XML Schema内置的简单类型的指令表的一部分定义的。

    在继续查阅购买订单模式文档之前,我们暂时离题来提一下实例文档和购买订单模式文档之间的联系。观察实例文档你可以看到购买订单模式文档并没有被提及。一个实例文档实际上不需要引用模式文档,当然尽管很多实例文档确实引用了,为了使这第一节简单化,我们一开始选择不引用。并且假设任何实例文档的处理器即使从实例文档中得不到任何信息,也能够包含购买订单模式文档的处理。在后面的章节,我们将介绍联系实例文档和模式文档的外部机制。

购买订单模式文档

购买订单模式文档包含在文件po.xsd中:


po.xsd,购买订单的Schema文档

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

 <xsd:annotation>
  <xsd:documentation xml:lang="en">
   Purchase order schema for Example.com.
   Copyright 2000 Example.com. All rights reserved.
  </xsd:documentation>
 </xsd:annotation>

 <xsd:element name="purchaseOrder" type="PurchaseOrderType"/>

 <xsd:element name="comment" type="xsd:string"/>

 <xsd:complexType name="PurchaseOrderType">
  <xsd:sequence>
   <xsd:element name="shipTo" type="USAddress"/>
   <xsd:element name="billTo" type="USAddress"/>
   <xsd:element ref="comment" minOccurs="0"/>
   <xsd:element name="items"  type="Items"/>
  </xsd:sequence>
  <xsd:attribute name="orderDate" type="xsd:date"/>
 </xsd:complexType>

 <xsd:complexType name="USAddress">
  <xsd:sequence>
   <xsd:element name="name"   type="xsd:string"/>
   <xsd:element name="street" type="xsd:string"/>
   <xsd:element name="city"   type="xsd:string"/>
   <xsd:element name="state"  type="xsd:string"/>
   <xsd:element name="zip"    type="xsd:decimal"/>
  </xsd:sequence>
  <xsd:attribute name="country" type="xsd:NMTOKEN"
     fixed="US"/>
 </xsd:complexType>

 <xsd:complexType name="Items">
  <xsd:sequence>
   <xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name="productName" type="xsd:string"/>
      <xsd:element name="quantity">
       <xsd:simpleType>
        <xsd:restriction base="xsd:positiveInteger">
         <xsd:maxExclusive value="100"/>
        </xsd:restriction>
       </xsd:simpleType>
      </xsd:element>
      <xsd:element name="USPrice"  type="xsd:decimal"/>
      <xsd:element ref="comment"   minOccurs="0"/>
      <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
     </xsd:sequence>
     <xsd:attribute name="partNum" type="SKU" use="required"/>
    </xsd:complexType>
   </xsd:element>
  </xsd:sequence>
 </xsd:complexType>

 <!-- Stock Keeping Unit, a code for identifying products -->
 <xsd:simpleType name="SKU">
  <xsd:restriction base="xsd:string">
   <xsd:pattern value="\d{3}-[A-Z]{2}"/>
  </xsd:restriction>
 </xsd:simpleType>

</xsd:schema>
 
    购买订单模式文档由一个schema元素和一系列子元素组成,大多数子元素为element, complexType, 和simpleType,这些决定了在实例文档中的元素的表现方式和内容。

    通过出现在schema元素中的命名空间声明xmlns:xsd="http://www.w3.org/2001/XMLSchema",在模式文档中的每一个元素都有一个与XML Schema命名空间相联系的命名空间前缀"xsd:".尽管任何前缀都能够被使用,但是,前缀"xsd:"被约定用于表示XML Schema命名空间。通过使用同样的前缀,这样同样的关联也出现在内置的简单类型的名字中。例如,xsd:string.这种形式的关联的目的是用来标识元素和简单类型是属于XML Schema语言的词汇表而不是模式文档作者自己的词汇表。为了在这里清楚表示,我们仅提及元素的名字和简单类型(如simpleType)而忽略了它们的前缀"xsd:".

复合类型定义,元素和属性声明

    在XML Schema中,对于允许元素有他们自己的内容以及可以携带自身属性的复合类型与那些不能够有元素内容和属性的简单类型之间,有着基本的不同。而在实例文档中,对于能建立新的类型(无论简单和复杂)的定义和允许元素和属性有特定的名字和类型(无论是简单还是复杂)的声明之间,也有着显著的差别。在这一节中,我们将针对如何定义复合类型,以及如何声明使用复合类型的元素及其属性。

    新的复合类型使用complexType元素来定义,这样的定义典型的包含一组元素声明,元素引用和属性声明。这些元素声明与其说是它们自身的类型,不如说是一由相关模式控制的名与控制这些名在实例文档中的表现形式的约束之间的关联。元素使用element元素声明,同时属性使用attribute来声明。举例来说,USAddress被定义为一个复合类型并且在USAddress定义中我们看到五个元素的声明和一个属性的声明。


<xsd:complexType name="USAddress" >
  <xsd:sequence>
   <xsd:element name="name"   type="xsd:string"/>
   <xsd:element name="street" type="xsd:string"/>
   <xsd:element name="city"   type="xsd:string"/>
   <xsd:element name="state"  type="xsd:string"/>
   <xsd:element name="zip"    type="xsd:decimal"/>
  </xsd:sequence>
  <xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>
 </xsd:complexType>
 
    这个定义的结果将是,在实例文档中出现的任何类型声明为USAddress的元素(比如在po.xml中的shiptTo)必须包含五个元素和一个属性。这些元素必须被命名为name、street、city、state和zip,这些名称就如同在模式声明中name属性的值所指的那样。并且这些属性必须按照模式声明中的同样的顺序出现。前四个元素必须包含一个字符串元素内容而第五个必须包含一个十进制数字类型的元素内容。声明为USAddress类型的元素可以带有一个country属性,该属性必须包含字符串"US".

    USAddress类型定义仅仅包含引用简单类型的声明:string、decimal 和NMTOKEN.与之对比,PurchaseOrderType类型定义则包含了引用复合类型的元素声明,如USAddress,虽然两个类型声明都使用同样的type属性来标识类型,而无需管类型是简单的还是复合的。

<xsd:complexType name="PurchaseOrderType">
  <xsd:sequence>
   <xsd:element name="shipTo" type="USAddress"/>
   <xsd:element name="billTo" type="USAddress"/>
   <xsd:element ref="comment" minOccurs="0"/>
   <xsd:element name="items"  type="Items"/>
  </xsd:sequence>
  <xsd:attribute name="orderDate" type="xsd:date"/>
 </xsd:complexType>
 
    在PurchaseOrderType的类型定义中,对于shipTo 和 billTo这两个子元素的声明,它们将不同的元素名字和相同的复合类型相关联,这个复合类型是USAddress.这个定义的结果是,如果在实例文档中出现的任何元素(如po.xml中),当元素类型被声明为PurchaseOrderType时,那么这个元素必须包含两个名为shipTo 和billTo的元素,这两个元素都要包含五个子元素(name、street、city、state和zip),这五个子元素是作为USAddress声明的一部分而出现的。应USAddress的相关类型定义,shipTo和billTo元素也可以包含country属性。

    PurchaseOrderType类型定义包含了一个orderDate属性声明,就像在UAAddress中的country属性声明一样,它被标识为一个简单类型,实际上,所有的属性声明必须引用简单类型。这是因为不像元素声明,属性不能包含其他元素或者其他属性。迄今为止我们描述的元素声明对于每一个名字都和一个现存的类型定义相关联。然而有时候,使用一个现存的元素比定义一个新的元素更方便。

<xsd:element ref="comment" minOccurs="0"/>
 


    这个声明定义引用了一个现存的元素comment,该元素在购买订单模式文档中的其他地方有定义。一般的来说,ref属性的值必须指向一个全局元素,一般来说,应当是在下面声明的而不是作为复合类型定义的一部分声明的。这个声明的结果为一个叫comment的元素可以出现在实例文档的关于这个定义的相关部分中,他的内容必须和那个被引用的元素的类型一致,在这个情况下是" string"。

出现约束

    我们看到,在前面中的元素声明中minOccurs属性的值为0 ,所以comment元素在PurchaseOrderType类型中是一个可选项。一般的来说,当minOccurs的值为1或者更多时,一个元素就必须出现。一个元素可以出现的最大数量由声明中的maxOccurs属性所决定的。这个值也许是一个正的整型如41,或者以"unbounded"的形式来表明不限最大的出现数量。minOccurs和maxOccurs属性的默认值是1.因此,当一个元素如comment,没有定义maxOccurs属性,元素不可以出现超过一次。如果你仅仅指定了minOccurs属性的值,它必须小于等于maxOccurs的默认值,也就是说minOccurs如果单独出现,其取值只能为0或者1.同样的,如果你只指定了maxOccurs属性,它必须大于等于minOccurs的默认值,也就是必须取值为1或者更多。如果两个属性都被省略了,那么元素必须出现且仅出现一次。

    而对于属性而言,它可以出现一次或者更本不出现,不会有其他的出现次数,所以指定属性出现次数的语法与元素的语法有所不同。特别的,属性声明能够使用一个use属性来指明属性是否需要出现(参阅po.xsd中partNum属性的声明)。

    属性和元素的默认值都是使用default属性来声明,不过这个属性在不同的情况下有些许不同的语义表示结果。当一个属性使用默认值来声明的时候,如果属性在实例文档中出现了,那么属性的值就是属性在实例文档中出现的那个值。如果属性没有在实例文档中出现,模式 处理器将认为这个属性的值等于声明中default属性的值。需要注意的是,属性默认值只在属性本身为"可选的"时候才有意义,如果在声明中,即指定了默认值,同时又设置了use属性为除"optional"以外的其他值的话,处理器就会产生错误。

    而当一个元素声明中有默认值定义的时候,模式处理器在处理默认的元素值的时候,与处理属性的默认值相比有一些不同。如果实例文档中元素出现且带有自身的内容的时候,元素的值就是是实例文档中元素的内容,如果元素没有内容,那么模式处理器就认为这个元素的值(内容)等于声明中default属性的值。然而,如果元素在实例文档中并不出现,模式处理器则更本不认为该元素出现。总而言之,元素和属性默认值之间的区别可以认为是:当属性不出现时默认的属性值被应用,当元素内容为空的时候,默认的元素值被应用。

    属性和元素声明中都使用到fixed属性来确保属性和元素被设置为特殊的值,如po.xsd中包含了一个country属性的声明,这个country属性声明就有一个fixed属性,值为US.这个声明意味着在实例文档中country属性的出现是可选的(use属性的默认值是optional),但是如果属性出现,他的值必须为"US",如果属性不出现,模式处理器将自动设置country属性值为"US".需要注意的是,fixed值的概念和default值的概念是互斥的。所以如果同时声明fixed和default属性就会令模式处理器产生一个错误。

    在元素和属性声明中用于约束他们出现行为的属性的值被概括地罗列在下表中:

元素 - 使用(minOccurs, maxOccurs) fixed, default  属性 - 使用use, fixed, default  注解  
(1, 1) -, - required, -, - 元素/属性必须出现一次,它可以有任何值。 
(1, 1) 37, - Required, 37, - 元素属性必须出现一次,他的值为37。 
(2, unbounded) 37, - 无相关描述 元素必须出现两次或者多次,他的值必须为37,一般说来,minOccurs 和maxOccurs可以为正数,maxOccurs可以为"unbounded"。 
(0, 1) -, - optional, -, - 元素/属性可以出现一次,他可以有任何值。 
(0, 1) 37, - optional, 37, - 元素/属性可以出现一次,如果出现他的值必须为37,如果不出现他的值为37。 
(0, 1) -, 37 optional, -, 37 元素/属性可以出现一次,如果不出现值为37,否则他的值为给出的值。 
(0, 2) -, 37 无相关描述 元素可以出现一次、两次或者更本不出现,如果元素不出现,则默认值不发生作用,如果出现并且他为空元素,则其值为37,否则值为实例中给出的值。一般说来,minOccurs 和maxOccurs可以为正数,maxOccurs可以为"unbounded"。 
(0, 0) -, - prohibited, -, - 元素/属性必须不出现。 

在这里,值得注意的是,在全局的元素和属性声明中,minOccurs、maxOccurs、use都没有出现。


全局元素和属性

    全局的元素和全局的属性是在全局声明时被建立的,全局声明都是作为元素的子元素出现的。一旦经过定义,全局元素或者全局属性可以像先前我们描述的那样使用ref属性在一个或多个声明中引用。一个引用全局元素的声明,允许被引用的元素在实例文档中出现在引用这个元素的声明相关的元素中。所以,举例来说, po.xml中的comment元素同样可以在shipTo、billTo和items元素中出现,因为引用comment的复合类型定义的声明同样出现在这三个元素的声明中。

    一个全局元素的声明也允许元素在实例文档中以顶级的文档元素出现,因此purchaseOrder元素,在po.xsd中是作为一个全局元素声明的,能够作为po.xml.中的顶级元素出现。值得注意的是,基于这个基本原理, comment元素作为顶级元素出现在文档如po.xml中也是被允许的。

    关于使用全局的元素和属性有很多忠告,其中一个忠告是全局的声明不能够包含引用。全局的声明定义不能包含ref 属性,他们必须使用type 属性(或者,像我们简短描述的,跟随一个匿名的类型的定义)。第二个忠告是约束不能够放在全局声明中。尽管他们能够放在引用全局声明的局部声明中。换句话说,全局声明不能够包含minOccurs、maxOccurs、或者use属性。

命名冲突

    我们现在已经讨论了如何定义新的复合类型(比如PurchaseOrderType),声明元素(比如purchaseOrder)和声明属性(如orderDate)。这些行为一般都包含着命名,因此,问题自然就出现了:如果我们给两个对象赋予同样的名称会如何?答案取决于问题中的两个对象,尽管,一般来说两个对象越相近,他们越有可能引起冲突。

    这里有一些例子来说明什么时候同样的名称会导致问题的出现。如果两个对象都是类型,如果我们去定义了一个复合类型称为USStates,同时又定义了一个简单类型称为USStates,此时就出现了冲突。如果两个对象是类型和元素或者是类型或者属性,当我们定义了一个复合类型叫USAddress,同时我们又定义了一个元素称为USAddress,此时是没有冲突发生的。如果两个对象是不同类型的元素(一般的,并非是全局元素),当我们声明了一个元素名字作为USAddress类型的一部分并且第二个元素名字作为item类型的一部分,此时就没有冲突(类似的元素有时候称为局部元素声明)。最后,如果两个对象都是类型,你自己定义了其中的一个,而XML Schema规范内置定义了另外的一个,比如你自己定义了一个简单类型称为decimal,那么此时没有冲突发生。最后一个例子中之所以没有命名冲突发生的原因是,因为他们属于不同的命名空间,我们将在后讨论在XML Schema中的XML命名空间的使用。


简单类型

   在购买订单模式文档中,几个元素和属性被声明为简单类型,其中一些简单类型如 string 和decimal是XML Schema中内置的。而其他的一些则是源于(如果使用对象技术的语言,就是继承)内置的类型。举例来说,partNum属性的类型称为SKU(Stock Keeping Unit),是源于string.的。内置的简单类型和他们的后继版本都能够被用在所有的元素和属性声明中,下面的列表列举了所有的在XML Schema中内置的简单类型及其相应的例子。

简单类型  值示例  备注  
string Confirm this is electric   
normalizedString Confirm this is electric 参见 (3) 
token Confirm this is electric 参见 (4) 
byte -1, 126 参见 (2) 
unsignedByte 0, 126 参见 (2) 
base64Binary GpM7   
hexBinary 0FB7   
integer -126789, -1, 0, 1, 126789 参见 (2) 
positiveInteger 1, 126789 参见 (2) 
negativeInteger -126789, -1 参见 (2) 
nonNegativeInteger 0, 1, 126789 参见 (2) 
nonPositiveInteger -126789, -1, 0 参见 (2) 
int -1, 126789675 参见 (2) 
unsignedInt 0, 1267896754 参见 (2) 
long -1, 12678967543233 参见 (2) 
unsignedLong 0, 12678967543233 参见 (2) 
short -1, 12678 参见 (2) 
unsignedShort 0, 12678 参见 (2) 
decimal -1.23, 0, 123.4, 1000.00 参见 (2) 
float -INF, -1E4, -0, 0, 12.78E-2, 12, INF, NaN 等同于单精度32位浮点数,其中”NaN”表示”不是一个数字”。参见 (2) 
double -INF, -1E4, -0, 0, 12.78E-2, 12, INF, NaN 等同于双精度64位浮点数。参见 (2) 
boolean true, false1, 0   
time 13:20:00.000, 13:20:00.000-05:00 参见 (2) 
dateTime 1999-05-31T13:20:00.000-05:00 这个时间表示的含义是:1999年5月31日美东标准时间下午1:20,注意后面的-05:00表示这个时间比格林尼治时间早5个小时。参见 (2) 
duration P1Y2M3DT10H30M12.3S 这表示经过了1年2个月3天又10个小时30分钟12.3秒。 
date 1999-05-31 参见 (2) 
gMonth --05-- 表示5月。参见 (2) (5) 
gYear 1999 表示1999年。参见 (2) (5) 
gYearMonth 1999-02 表示1999年2月,而并不关心是几号。参见 (2) (5) 
gDay ---31 表示31号。参见 (2) (5) 
gMonthDay --05-31 表示每个5月31号。参见 (2) (5) 
Name shipTo XML 1.0的Name类型 
QName po:USAddress XML命名空间的QName类型 
NCName USAddress XML命名空间的NCName类型,即一个不带命名空间前缀修饰的QName 
anyURI http://www.example.com/, http://www.example.com/doc.html#ID5   
language en-GB, en-US, fr XML 1.0中定义的合法语言代码 
ID   XML 1.0中定义的ID属性类型。参见 (1) 
IDREF   XML 1.0中定义的IDREF属性类型。参见 (1) 
IDREFS   XML 1.0中定义的IDREFS属性类型。参见 (1) 
ENTITY   XML 1.0中定义的ENTITY属性类型。参见 (1) 
ENTITIES   XML 1.0中定义的ENTITYS属性类型。参见 (1) 
NOTATION   XML 1.0中定义的NOTATION属性类型。参见 (1) 
NMTOKEN US, Brésil XML 1.0中定义的NMTOKEN属性类型。参见 (1) 
NMTOKENS US UK, Brésil Canada Mexique XML 1.0中定义的NMTOKENS属性类型,即一个使用空格作为元素分隔的NMTOKEN列表。参见 (1) 
注意:

    为了在XML Schema和XML 1.0 DTD之间保持兼容,简单类型ID、IDREF、IDREFS、ENTITY、ENTITIES、NOTATION、NMTOKEN、NMTOKENS只能用在属性定义中; 
这个类型的值能够表示为不止一种格式,如100和1.0E2都是有效的float格式,它们都表示”一百”这个数值。然而,对于这个类型而言,已经为其定义了规范的格式规则。 
换行符、制表符和回车符在normalizedString中将会在处理前被转化成空格字符 
作为normalizedString,相邻的空格字符将会被合并为一个空格字符,第一个和最后的空格将被移走 
“g”前缀表示罗马历的时间和年代。 
 

    新的简单类型通过从现有的简单类型(内置的简单类型以及源于内置简单类型的简单类型)引出定义。特别的,我们通过重新约束一个现存的简单类型来引出一个新的简单类型。换句话说,新类型的合法值范围是现有类型的值范围的子集。我们使用simpleType元素来定义和命名新的简单类型,我们使用restriction元素来指出现有的基类型。并且用它来标识约束值范围的细节。

   假设我们希望建立一个新的整数类型称为myInteger,他的值范围为10000到99999。我们的定义应当基于简单类型integer,然后定义他的值范围为10000到99999。为了定义myInteger,我们这样来约束integer的范围(参见下图):


使用基类型来定义新的简单类型

<xsd:simpleType name="myInteger">
  <xsd:restriction base="xsd:integer">
    <xsd:minInclusive value="10000"/>
    <xsd:maxInclusive value="99999"/>
  </xsd:restriction>
</xsd:simpleType>
 


    上面的例子显示了一个由一个基本类型定义和两个值域区间方面描述的组合,通过这三个要素来对myInteger实施了定义。
 
    而先前的购买订单模式文档则包含了其他的更详细的定义简单类型的例子。一个叫SKU的新简单类型(参见下图)是从(通过约束)简单类型string引出的。此外,我们使用一个称为pattern的描述以及pattern的正则表达式值"\d{3}-[A-Z]{2}"来约束SKU的值。其中,该正则表达式值的语义为:3个数字后面跟着一个连字号接着跟着两个大写的英文字母"。


<xsd:simpleType name="SKU">
  <xsd:restriction base="xsd:string">
    <xsd:pattern value="\d{3}-[A-Z]{2}"/>
  </xsd:restriction>
</xsd:simpleType>
 


    XML Schema定义了15用于简单类型定义描述的词汇。在这些词汇中,enumeration是特别有用的,他能够被用于约束除boolean类型之外的几乎每一个简单类型。enumeration限制简单类型的值为一系列不同的枚举值。举例来说,我们可以使用enumeration来定义一个新类型称为USState(参见下图),USState是从string引出的,同时它的值必须为美国州的缩写。


<xsd:simpleType name="USState">
  <xsd:restriction base="xsd:string">
    <xsd:enumeration value="AK"/>
    <xsd:enumeration value="AL"/>
    <xsd:enumeration value="AR"/>
    <!-- and so on ... -->
  </xsd:restriction>
</xsd:simpleType>
 


    USState将会在现在使用的state元素声明中成为string类型的一个非常好的替换品。通过使用这个替换品可以使state元素具有合法值的校验能力。举例来说,billTo和shipTo元素的子元素state,将会被限制在AK,AL,AR等等中。注意到对于特定类型的列举值必须是唯一的。



列表类型(List Type)

    除了在前面描述简单类型的那个表格中列出的原子类型(这些原子类型可用于组合成绝大多数的其他类型,包括其他的简单类型和复合类型)外,XML Schema中在简单类型范畴中还有列表类型的概念。(原子类型、列表类型以及将在下一节中描述的组合类型,总称为简单类型)。一个原子类型的值在XML Schema中是不可分割的。举例来说,NMTOKEN值US是不可分割的,US的任何部分,如字母S本身都是没有意义的。与之相比较,列表类型则是由一组原子类型组成,因此它的每一个部分(原子)本身都是有意义的。举例来说NMTOKENS是个列表类型。这个类型的元素将是NMTOKEN的列表,不同的NMTOKEN值间使用空格分隔,如"US UK FR"。XML Schema有三个内置的列表类型,他们是NMTOKENS、IDREFS和ENTITIES。

    除了使用内置的列表类型之外,你还可以通过引用现有的原子类型来建立新的列表类型(你不可以使用现有的列表类型来建立新的列表类型。也不能使用复合类型来建立新的列表类型)。举例来说,我们可以建立一个名为myInteger的列表类型,并在实例文档中使用它(参见下图)。其中下图中的后半部分即为实例文档中与列表类型listOfMyIntType相一致的实例元素。


<!-- Schema Fragment -->
<xsd:simpleType name="listOfMyIntType">
  <xsd:list itemType="myInteger"/>
</xsd:simpleType>

<!-- Instance Fragment -->
<listOfMyInt>20003 15037 95977 95945</listOfMyInt>
 


     一些用于描述的参数能够被应用到列表类型的定义中,它们是:length、minLength、maxLength和enumeration。举例来说,如果我们想定义一个列表,这个列表正好包含了六个美国的州名(SixUSStates)。我们首先从USState定义了一个新的列表类型,称为USStateList,然后我们通过限制USStateList 只有六个项来导出SixUSStates。具体的定义可参见下图。


<!-- Schema Fragment -->
<xsd:simpleType name="USStateList">
 <xsd:list itemType="USState"/>
</xsd:simpleType>

<xsd:simpleType name="SixUSStates">
 <xsd:restriction base="USStateList">
  <xsd:length value="6"/>
 </xsd:restriction>
</xsd:simpleType>

<!-- Instance Fragment -->
<sixStates>PA NY CA NY LA AK</sixStates>
 


    类型为SixUSStates的元素必须有六个项,他们中的每一个必须是一个枚举类型USState的原子类型,在上图后半部分的实例文档中就是一个具体的应用例子。

    此时,我们需要注意的是,我们可以从原子类型string导出一个列表类型,然而,在一个string中也许会带有空格,而空格在一个列表类型实例中是作为分隔符使用的。所以当在使用基类型为string的列表类型时,应当格外小心。举例来说,假设我们定义了一个length取值为3的列表类型,同时这个列表类型是基于类型string。以下的由三个元素组成的列表是合法的:"Asie Europe Afrique",而下面的由三个元素组成的列表则是不合法的:"Asie Europe Amérique Latine"。

    即使"Amérique Latine"在列表外可以作为单独的一个字符串存在,但当它包含在列表中,在Amérique和Latine之间的空格使得第四个项被有效地生成了,因此后面的那个例子不符合只有三个项的列表类型定义。

联合类型(Union Type)

    应用原子类型和列表类型,一个元素或者属性的值可以为一个或者多个原子类型(列表类型)的实例。与之相比较,如果应用联合类型,一个联合类型包含了多个原子类型或者列表类型,而应用了联合类型的元素或是属性的值可以是这些原子类型或列表类型中的一个类型的实例。为了显示这点,我们建立一个用于表示美国的州的,为两个字母缩写或者数字列表的联合类型。zipUnion联合类型由一个原子类型和一个列表类型构成的(参见下图)。


<!-- Schema Fragment -->
<xsd:simpleType name="zipUnion">
  <xsd:union memberTypes="USState listOfMyIntType"/>
</xsd:simpleType>

<!-- Instance Fragment -->
<zips>CA</zips>
<zips>95630 95977 95945</zips>
<zips>AK</zips>
 


    当我们在定义一个联合类型时,元素union的memberTypes属性的值包含了联合类型中所有类型的列表。现在,假定我们声明了一个zipUnion类型的元素,称为zips,zips元素有效的实例可参见上图。

此外,对于联合类型而言,还有两个描述性质的参数pattern和enumeration也可以应需要使用。

 

匿名类型定义


    使用XML Schema,我们能够通过定义一系列具有名称的类型,如PurchaseOrderType类型,然后声明一个元素,比如purchaseOrder,通过使用"type="这样的构造方法来应用类型。这种类型的模式构造非常直截了当,但有些不实用。特别是,如果你定义了许多只应用一次而且包含非常少约束的类型,在这些情况下,一个类型应该能够被更简单的定义。这样的简单定义通常的形式是一个节省了名称和外部引用开销的匿名类型。

    在po.xsd(参见下图)中类型Items的定义中,有两个元素声明使用了匿名类型定义,它们是item和quantity.一般的来说,你能够通过元素中是否包含"type="这个属性来判断匿名元素定义(或者是匿名属性定义),而另方面,如果出现无名称的类型定义也可以认为是匿名元素(属性)定义。

<xsd:complexType name="Items">
 <xsd:sequence>
  <xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
   <xsd:complexType>
    <xsd:sequence>
     <xsd:element name="productName" type="xsd:string"/>
     <xsd:element name="quantity">
      <xsd:simpleType>
       <xsd:restriction base="xsd:positiveInteger">
        <xsd:maxExclusive value="100"/>
       </xsd:restriction>
      </xsd:simpleType>
     </xsd:element>
     <xsd:element name="USPrice"  type="xsd:decimal"/>
     <xsd:element ref="comment"   minOccurs="0"/>
     <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
    </xsd:sequence>
    <xsd:attribute name="partNum" type="SKU" use="required"/>
   </xsd:complexType>
  </xsd:element>
 </xsd:sequence>
</xsd:complexType>
 


   在item元素中,它被定义为一个复合匿名类型,该复杂类型是由productName、quantity、USPrice、comment、shipDate元素和一个称为partNum的属性组成的。在quantity元素中,他有一个简单匿名类型,从integer类型中引出,他的值范围为1到99。


元素内容


    购买订单的模式文档中包含了很多元素类型定义的例子:有元素包含其他元素的(如items),有元素包含其他元素和属性的(如shipTo)以及元素包含一个简单类型值的(如USPrice)。然而,我们没有看见包含了属性并且只包含一个简单类型值的元素,也没有看见包含了其他元素,同时也有文本内容,两者混在一起的元素,也没有看见更本不包含内容的元素。在本节,我们将要看看元素的内容模型的这些变化。


从简单类型到复合类型


    让我们首先考虑一下,如何声明包含了一个属性,同时拥有简单类型值的元素。在一个实例文档中,此类的元素就像下面的形式: <internationalPrice currency="EUR">423.46</internationalPrice>

    让我们从购买订单模式文档中的USPrice元素声明开始: <xsd:element name="USPrice" type="decimal"/>

    现在我们如何为这个元素定义添加一个属性呢? 我们以前说过,简单类型不能有属性,而decimal是简单类型。因此,我们必须定义一个复合类型来携带属性声明。然而,同时我们也想具有简单类型decimal的元素内容。所以我们最初的问题转化为:我们如何定义一个基于简单类型decimal的复合类型? 答案是,从简单类型decimal中引出一个新的复合类型(参见下图)。

<xsd:element name="internationalPrice">
  <xsd:complexType>
   <xsd:simpleContent>
    <xsd:extension base="xsd:decimal">
     <xsd:attribute name="currency" type="xsd:string"/>
    </xsd:extension>
   </xsd:simpleContent>
  </xsd:complexType>
 </xsd:element>
 


    我们使用complexType 元素来开始定义一个新的(匿名的)类型。为了表示新类型的内容模型只包括字符数据而没有元素,我们使用simpleContent元素来实施定义。最后,我们通过扩展简单的decimal类型引出新的类型。扩展包括使用标准属性声明来添加一个currency属性。


混合内容


    购买订单模式文档的构造也许会被特征化为元素包含子元素、并且最深的子元素包含字符数据。当然,XML Schema也为模式文档的构造提供了另一类支持:字符数据可以和子元素同时出现,也就是说字符数据并不是被限制在最深的元素中。

    为了显示这点,考虑下面的这个使用XML表示的客户信笺的片断,该片断包含了一些购买订单相同的元素(参见下图)。

<letterBody>
<salutation>Dear Mr.<name>Robert Smith</name>.</salutation>
Your order of <quantity>1</quantity> <productName>Baby
Monitor</productName> shipped from our warehouse on
<shipDate>1999-05-21</shipDate>. ....
</letterBody>
 


    请注意在元素之间的文本和他们的子元素。在这里,文本出现在元素salutation、quantity、productName和shipDate之间,这些元素都是LetterBody的子元素。并且在letterBody孙子元素name旁边也有文本出现。

<xsd:element name="letterBody">
 <xsd:complexType mixed="true">
  <xsd:sequence>
   <xsd:element name="salutation">
    <xsd:complexType mixed="true">
     <xsd:sequence>
      <xsd:element name="name" type="xsd:string"/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
   <xsd:element name="quantity"    type="xsd:positiveInteger"/>
   <xsd:element name="productName" type="xsd:string"/>
   <xsd:element name="shipDate"    type="xsd:date" minOccurs="0"/>
   <!-- etc. -->
  </xsd:sequence>
 </xsd:complexType>
</xsd:element>
 
    出现在客户信笺中的元素是使用我们先前看到的element 和complexType元素构造来声明的,他们的类型也是用这种方法定义的(参见上图)。

    注意到在XML Schema中,混合模型与XML 1.0的混合模型有着根本的区别。在XML Schema下面的混合模型,子元素在一个实例中出现的顺序和数量必须与子元素在模型中说明的顺序和数量一致。与之相对,在XML1.0混合模型下,出现在实例中的子元素的顺序和数量不能被限制。总而言之,XML Schema提供了充分的混合模型的校验而XML1.0只提供了部分的模式校验。

空内容


    现在假设我们想让internationalPrice元素用属性值来传送流通的单位和价格,而不是象先前用一个属性值以及元素内容值来表示。举例来说: <internationalPrice currency="EUR" value="423.46"/>

    这样的元素根本没有内容,他的内容模型是空。为了定义内容是空的类型,我们可以通过这样的方式:首先我们定义一个元素,它只能包含子元素而不能包含元素内容,然后我们又不定义任何子元素,依靠这样的方式,我们就能够定义出内容模型为空的元素。

<xsd:element name="internationalPrice">
 <xsd:complexType>
  <xsd:complexContent>
   <xsd:restriction base="xsd:anyType">
    <xsd:attribute name="currency" type="xsd:string"/>
    <xsd:attribute name="value"    type="xsd:decimal"/>
   </xsd:restriction>
  </xsd:complexContent>
 </xsd:complexType>
</xsd:element>
 


    在上图这个例子中,我们定义了一个匿名类型,它包含的是complexContent,即只包含子元素。ComplexContent元素表明我们想要限制或者扩展一个复合类型的内容模型,并且类型为anyType的restriction元素声明了两个属性,而没有引入任何元素内容。使用这种方法声明的InternationalPrice元素就得以像上面例子里所显示的那样合理地出现在实例文档中。

    前述上图中的关于空内容元素的语法相对有点冗长。我们可以通过更简洁的声明方式来声明internationalPrice元素(参见下图)。

<xsd:element name="internationalPrice">
 <xsd:complexType>
  <xsd:attribute name="currency" type="xsd:string"/>
  <xsd:attribute name="value" type="xsd:decimal"/>
 </xsd:complexType>
</xsd:element>
 


     因为一个不带有simpleContent 或者complexContent的复合类型定义,会被解释为带有类型定义为anyType的complexContent,这是一个默认的速记方法,所以这个简洁的语法可以在模式处理器中工作。


anyType

    anyType表示一个称为ur-type的抽象,它是导出所有简单类型和复合类型的基类型。一个anyType类型不以任何形式约束其包含的内容。我们可以象使用其他类型一样,使用anyType,如: <xsd:element name="anything" type="xsd:anyType"/>

    用这个方式声明的元素是不受约束的。所以元素的值可以为423.46,也可以为任何其他的字符序列,或者甚至是字符和元素的混合。实际上,anyType是默认类型,所以上面的可以被重写为:<xsd:element name="anything"/>

    如果需要表示不受约束的元素内容,举例来说在元素包含散文,其中可能需要嵌入标签来支持国际化的表示,那么默认的声明(无约束)或者有些微约束的形式会很合适。

注释

    为了方便其他读者和应用来理解模式文档,XML Schema提供了三个元素用来注释。在购买订单模式文档中,我们在documentation元素中放置了一个基本的模式描述和版权信息,这是放置适合人阅读的信息的推荐位置。我们推荐你在任何的documentation元素中使用xml:lang属性来表示这些描述信息使用的语言。另一个替代的方式是,你可以通过在schema元素中放置xml:lang属性来指明语言信息。

    我们并没有在购买订单模式文档中使用元素appInfo,这个元素能够用来为工具、样式表和其他应用提供信息。在XML Schema Part 2:Datatypes中有一个描述简单类型的模式文档,它就是一个使用appInfo很有趣的例子。documentation和 appInfo是作为annotation元素的子元素出现的,这个元素自己出现在大多数schema构造的开头。为了显示这点,下面的例子显示了如何在元素声明开头使用annotation元素声明,这是一个复合类型的定义(参见下图)。


<xsd:element name="internationalPrice">
 <xsd:annotation>
  <xsd:documentation xml:lang="en">
      element declared with anonymous type
  </xsd:documentation>
 </xsd:annotation>
 <xsd:complexType>
  <xsd:annotation>
   <xsd:documentation xml:lang="en">
       empty anonymous type with 2 attributes
   </xsd:documentation>
  </xsd:annotation>
  <xsd:complexContent>
   <xsd:restriction base="xsd:anyType">
    <xsd:attribute name="currency" type="xsd:string"/>
    <xsd:attribute name="value" type="xsd:decimal"/>
   </xsd:restriction>
  </xsd:complexContent>
 </xsd:complexType>
</xsd:element>
 


    annotation元素也会出现在其他模式构造的开头,如那些通过元素schema、simpleType和attribute来展示的模式构造。


构造内容模型


    在购买订单模式文档中复合类型的定义都是定义了一系列的元素,这些元素在实例文档中都必须出现。在这些类型的内容模型中,单个元素的是否出现是可选的,这我们可以通过属性值"minOccurs=0'(如在comment中)来实现。当然我们也可以通过对minOccurs和maxOccurs赋予不同的值来实施其他不同的约束限制。XML Schema也支持对在内容模型中出现的元素组的约束。我们需要注意的是,约束是不能应用在属性声明上的。XML Schema允许定义和命名元素组。所以元素能够用来建立复合类型的内容模型,未命名的元素组也能够和命名的元素组一起被定义。他们能够被约束为他们以声明中的相同顺序序列在实例文档中出现。或者,他们能够被约束为只有一个元素可以出现在实例文档里面。

    为了显示这点,我们在购买订单模式文档中的purchaseOrderType定义中引入两个元素组定义。这样,购买订单就可以有两种选择来描述地址:第一种是包含彼此独立的送货地址和收款地址,第二种情况则是仅包含一个简单的地址,这个地址即是送货地址也是收款地址(参见下图)。

<xsd:complexType name="PurchaseOrderType">
 <xsd:sequence>
  <xsd:choice>
   <xsd:group ref="shipAndBill"/>
   <xsd:element name="singleUSAddress" type="USAddress"/>
  </xsd:choice>
  <xsd:element ref="comment" minOccurs="0"/>
  <xsd:element name="items"  type="Items"/>
 </xsd:sequence>
 <xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>

<xsd:group name="shipAndBill">
  <xsd:sequence>
    <xsd:element name="shipTo" type="USAddress"/>
    <xsd:element name="billTo" type="USAddress"/>
  </xsd:sequence>
</xsd:group>
 


    对于choice组元素而言,在实例中仅仅允许出现这个组中的一个子内容。对于上图中的例子而言,第一个子内容是一个内部group元素,引用以shipAndBill命名的元素组,这个元素组由元素序列shipTo、billTo组成。第二个子内容为singleUSAddress.因此,在一个实例文档中,purchaseOrder元素必须,要么包含一个billTo元素和一个shipTo元素,要么包含一个singleUSAddress元素。choice组后面跟着的是comment和items元素声明。元素和组的声明都是sequence 组的子内容。这样定义的效果是comment和items元素必须按顺序跟在地址元素后面。

    现在有第三种选择在组中包含元素:通过使用all元素定义的元素组,在组中所有的元素都可以出现一次或者更本不出现,而且他们能够以任何顺序出现。all组被限制放在任何内容模型的顶部,此外,all元素组的子内容必须都为独立元素(不能有组元素),在all元素定义的内容模型中的元素都不可以出现超过一次,也就是说minOccurs 和maxOccurs允许的值为"0"和"1".举例来说,为了允许purchaseOrder的子元素以任意的顺序出现,我们能够用下面的形式重新定义purchaseOrderType(参见下图):

<xsd:complexType name="purchaseOrderType">
  <xsd:all>
    <xsd:element name="shipTo" type="USAddress"/>
    <xsd:element name="billTo" type="USAddress"/>
    <xsd:element ref="comment" minOccurs="0"/>
    <xsd:element name="items"  type="Items"/>
  </xsd:all>
  <xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
 


 

   通过使用这个定义,一个comment元素可以选择出现在purchaseOrder中的不同位置,可以在shipTo、billTo和items元素之前或者之后出现,但他只能够出现一次。而且all组的约束不允许我们在组外面声明一个元素,因为这样可以允许它出现超过一次。XML Schema限制所有的all组必须作为内容顶部的唯一子元素出现,换句话说,下面的形式是不合法的(参见下图):

<xsd:complexType name="PurchaseOrderType">
 <xsd:sequence>
  <xsd:all>
    <xsd:element name="shipTo" type="USAddress"/>
    <xsd:element name="billTo" type="USAddress"/>
    <xsd:element name="items"  type="Items"/>
  </xsd:all>
  <xsd:sequence>
   <xsd:element ref="comment" minOccurs="0" maxOccurs="unbounded"/>
  </xsd:sequence>
 </xsd:sequence>
 <xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
 


    最后,在内容模型中被命名或未被命名的元素组(分别由group、choice、sequence、all所表现)可以带有minOccurs 和maxOccurs属性。通过使用这些特性,XML Schema可以完全表现DTD所能表现的功能。而且,all组也提供了额外的表达能力。


属性组


    假设我们想在购买定单里面为每个物品表示更多的信息,例如,每个物品的重量和期望的运输方式。我们希望能够通过为item元素的(匿名)类型定义添加weightKg和shipBy属性声明来做到这点(参见下图)。

<xsd:element name="Item" minOccurs="0" maxOccurs="unbounded">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:element   name="productName" type="xsd:string"/>
    <xsd:element   name="quantity">
     <xsd:simpleType>
      <xsd:restriction base="xsd:positiveInteger">
       <xsd:maxExclusive value="100"/>
      </xsd:restriction>
     </xsd:simpleType>
    </xsd:element>
    <xsd:element name="USPrice"  type="xsd:decimal"/>
    <xsd:element ref="comment"   minOccurs="0"/>
    <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
   </xsd:sequence>
   <xsd:attribute name="partNum"  type="SKU" use="required"/>
   <!-- add weightKg and shipBy attributes -->
   <xsd:attribute name="weightKg" type="xsd:decimal"/>
   <xsd:attribute name="shipBy">
    <xsd:simpleType>
     <xsd:restriction base="xsd:string">
      <xsd:enumeration value="air"/>
      <xsd:enumeration value="land"/>
      <xsd:enumeration value="any"/>
     </xsd:restriction>
    </xsd:simpleType>
   </xsd:attribute>
  </xsd:complexType>
</xsd:element>
 


    或者,我们可以建立一个被命名的属性组来包含所有item元素所期望的属性,并且在item元素声明中通过名字来引用这个属性组(参见下图):

<xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
 <xsd:complexType>
  <xsd:sequence>
   <xsd:element name="productName" type="xsd:string"/>
   <xsd:element name="quantity">
    <xsd:simpleType>
     <xsd:restriction base="xsd:positiveInteger">
      <xsd:maxExclusive value="100"/>
     </xsd:restriction>
    </xsd:simpleType>
   </xsd:element>
   <xsd:element name="USPrice"  type="xsd:decimal"/>
   <xsd:element ref="comment"   minOccurs="0"/>
   <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
  </xsd:sequence>

  <!-- attributeGroup replaces individual declarations -->
  <xsd:attributeGroup ref="ItemDelivery"/>
 </xsd:complexType>
</xsd:element>

<xsd:attributeGroup name="ItemDelivery">
  <xsd:attribute name="partNum"  type="SKU" use="required"/>
  <xsd:attribute name="weightKg" type="xsd:decimal"/>
  <xsd:attribute name="shipBy">
    <xsd:simpleType>
     <xsd:restriction base="xsd:string">
      <xsd:enumeration value="air"/>
      <xsd:enumeration value="land"/>
      <xsd:enumeration value="any"/>
     </xsd:restriction>
    </xsd:simpleType>
  </xsd:attribute>
</xsd:attributeGroup>
 


    通过这种方法来使用属性组,可以提高模式文档的可读性,同时也便于更新模式文档。这是因为一个属性组能够在一个地方定义和编辑,同时能够在多个定义和声明中被引用。注意到一个属性组可以包含其他属性组,同时还要注意到属性组的声明和引用必须在复合类型定义的最后。


空值(Nil)


    我们再回到前面的po.xml来,这个购买定单中购买的物品之一Lawnmower,是没有shipDate元素的。在我们的这个应用背景中,模式文档和实例文档的作者可能故意安排这样的缺席用来表示这个item还没有被运出。但是,一般的来说,缺少一个元素并没有任何特别的意义:它也许表示信息不可知或者不适用或者因为其他的原因而不存在。有时常常是通过增加一个元素而不是通过缺少一个元素,来明确地表达关于未运出的物品、未知信息或者不适用信息等。举例来说,也许想要使用一个元素来表示发送空值或者表示数据库中的空值,类似的情况可以使用XML Shema的空值机制来表现,这个机制允许一个元素以空值或者非空值出现。

<?xml version="1.0"?>
<purchaseOrder orderDate="1999-10-20">
    <shipTo country="US">
        <name>Alice Smith</name>
        <street>123 Maple Street</street>
        <city>Mill Valley</city>
        <state>CA</state>
        <zip>90952</zip>
    </shipTo>
    <billTo country="US">
        <name>Robert Smith</name>
        <street>8 Oak Avenue</street>
        <city>Old Town</city>
        <state>PA</state>
        <zip>95819</zip>
    </billTo>
    <comment>Hurry, my lawn is going wild!</comment>
    <items>
        <item partNum="872-AA">
            <productName>Lawnmower</productName>
            <quantity>1</quantity>
            <USPrice>148.95</USPrice>
            <comment>Confirm this is electric</comment>
        </item>
        <item partNum="926-AA">
            <productName>Baby Monitor</productName>
            <quantity>1</quantity>
            <USPrice>39.98</USPrice>
            <shipDate>1999-05-21</shipDate>
        </item>
    </items>
</purchaseOrder>
 
    XML Schema 空值机制包括一个空值信号。换句话说,作为元素内容而言,并没有没有真正的空值,代之的是一个说明元素的内容是空值的属性。为了显示这点,我们修改shipDate元素的声明,这样空值就能够被明确地告知用户了。 <xsd:element name="shipDate" type="xsd:date" nillable="true"/>

    为了在实例文档中明确的表示shipDate有一个空值,我们可以设置nil属性为真: <shipDate xsi:nil="true"></shipDate>

    nil属性是作为XML Schema命名空间的一部分来定义的,即"http://www.w3.org/2001/XMLSchema-instance",并且在实例文档中必须带有与命名空间相对应的前缀(一般定义为xsi:)出现。需要注意的是,空值机制仅仅适用于元素值,而不适用于属性值,一个元素有xsi:nil="true"可以没有任何元素内容但仍旧可以带有其他属性。

Copyrightc 2001 W3C,( MIT, INRIA, Keio),All Rights Reserved.

相关内容
赞助商链接