使用 XML Schema 定义元素的基本知识

新的 XML Schema 系统即将成为 W3C 推荐标准,目的是为了克服 DTD 的局限性(请参阅侧栏, DTD 的局限性),为 XML 文档提供丰富的语法结构。本文展示了模式的灵活性,说明如何使用 XML Schema 系统来定义最基本的 XML 文档构造块——元素。

XML Schema 比 DTD 更强大。为了说明 XML Schema 机制的强大功能,下面三个程序清单简要比较了表示元素的不同方式。清单 1 给出了一个 XML 文档片段,清单 2 用 DTD 语法声明了这两个元素,清单 3 则是相应的 XML Schema 语法形式。要注意,清单 3 中所用的是相同的 XML 语法。通过模式,验证解析器可以检查元素 InvoiceNo 是否是正整数,元素 ProductID 的首字符是否为 A 到 Z 之间的字母,后面为六个阿拉伯数字。相反,引用 DTD 的验证解析器只能检查这些元素是否用字符串表示。

清单 1:XML 文档片段


<InvoiceNo>123456789</InvoiceNo>
<ProductID>J123456</ProductID>
清单 2:描述清单 1 中元素的 DTD 片段

<!ELEMENT InvoiceNo (#PCDATA)>
<!ELEMENT ProductID (#PCDATA)>
清单 3:描述清单 1 中元素的 XML Schema

<element name='InvoiceNo' type='positive-integer'/>
<element name='ProductID' type='ProductCode'/>
<simpleType name='ProductCode' base='string'>
  <pattern value='[A-Z]{1}d{6}'/>
</simpleType>

在 XML Schema 中使用名称空间
在这个协作的世界中,一个人可能处理来自多个其他团体的文档,而不同的团体可能希望以不同的方式表示他们的数据元素。此外,他们还可能在一个文档中引用不同团体创建的同名元素。如何区分相同名字的不同定义呢?XML Schema 使用名称空间区分这些定义。

DTD 的局限性
尽管作为描述结构化信息的一种机制,DTD 成功地为 SGML 和 HTML 开发人员服务了 20 年,但与 XML Schema 相比,它存在着严重的局限性。

DTD 要求元素由以下三种成分组成:

  • 文本字符串
  • 文本字符串与其他子元素的混合
  • 一组子元素
DTD 不使用 XML 语法,对类型和名称空间仅提供有限的支持。

一个给定的 XML Schema 定义了一组新名字,如元素名、类型名、属性名、属性组名,这些名字的定义和声明都写在模式中。清单 3 定义的名字包括 InvoiceNoProductIDProductCode

我们说模式中定义的名字属于它的 目标名称空间。名称空间本身有一个固定但没有限制的名字,必须符合 URL 语法。比如,对于 清单 3 中模式片段,您可以把名称空间的名字设为:http://www.SampleStore.com/Account

名称空间的名字语法容易让人混淆,尽管以 http:// 开始,那个 URL 并不指向一个包含模式定义的文件。事实上,这个 URL http://www.SampleStore.com/Account 根本没有指向任何文件,只是一个分配的名字。

模式中的定义和声明可能引用属于其他名称空间的名字。在本文中,我们称这些名称空间为 源名称空间。每个模式都有一个目标名称空间,但可能有多个源名称空间。名称空间的名字可能相当长,但在 XML 文档中通过 xmlns 声明可使用简写形式。为了说明这些概念,我们可以向前述 清单 4 中的示例模式中添加更多的内容。

清单 4:目标名称空间和源名称空间

<!--XML Schema fragment in file schema1.xsd-->

<xsd:schema targetNamespace='http://www.SampleStore.com/Account'
      xmlns:xsd='http://www.w3.org/1999/XMLSchema'
      xmlns:ACC= 'http://www.SampleStore.com/Account'>
<xsd:element name='InvoiceNo' type='xsd:positive-integer'/>
<xsd:element name='ProductID' type='ACC:ProductCode'/>
<xsd:simpleType name='ProductCode' base='xsd:string'>
  <xsd:pattern value='[A-Z]{1}d{6}'/>
</xsd:simpleType>

清单 4 的 XML Schema 中,targetNamespace 的名字是 http://www.SampleStore.com/Account,其中包含的名字有 InvoiceNoProductIDProductCodeschemaelementsimpleTypepatternstringpositive-integer 这些名字属于源名称空间 http://www.w3.org/1999/XMLSchema,通过 xmlns 声明缩写为 xsd。别名 xsd 没有任何特殊的地方,我们可以选择任何其他的名字。在本文后面的部分为了方便和简化起见,我们使用 xsd 代表名称空间 http://www.w3.org/1999/XMLSchema,在一些代码片段中省略了限定符 xsd。在这个例子中,targetNamespace 偶尔也作为一个源名称空间,因为要使用名字 ProductCode 定义其他的名字。

图 1:清单 4 中的名称空间
图 1: 清单 4 中的名称空间

清单 4 中的模式片段不需要指定源模式文件的位置。对于整个“模式的模式”,http://www.w3.org/1999/XMLSchema,不需要指定位置,因为它的位置是人所共知的。对于源名称空间 http://www.SampleStore.com/Account,也不需要指定位置,因为它恰好是该文件中定义的目标名称空间。为了更好地理解如何指定模式的位置和使用默认名称空间,看一看 清单 5 中扩展的例子。

清单 5:多个源名称空间,导入一个名称空间


<!--XML Schema fragment in file schema1.xsd-->
<schema targetNamespace='http://www.SampleStore.com/Account'
      xmlns='http://www.w3.org/1999/XMLSchema'
      xmlns:ACC= 'http://www.SampleStore.com/Account'
      xmlns:PART= 'http://www.PartnerStore.com/PartsCatalog'>
<import namespace='http://www.PartnerStore.com/PartsCatalog'
        schemaLocation='http://www.ProductStandards.org/repository/alpha.xsd'/>
<element name='InvoiceNo' type='positive-integer'/>
<element name='ProductID' type='ACC:ProductCode'/>
<simpleType name='ProductCode' base='string'>
  <pattern value='[A-Z]{1}d{6}'/>
</simpleType>
<element name='stickyGlue' type='PART:SuperGlueType'/>

清单 5 中多了一个名称空间引用: http://www.PartnerStore.com/PartsCatalog。这个名称空间不同于 targetNamespace 和标准名称空间。因此必须使用 import 声明元素引入,该元素的 schemaLocation 属性指明包含模式的文件位置。默认的名称空间是 http://www.w3.org/1999/XMLSchema,它的 xmlns 声明没有名字。每个非限定的名字如 schemaelement,都属于默认名称空间 http://www.w3.org/1999/XMLSchema。如果模式从一个名称空间中引用了多个名字,将其指定为默认名字空间更方便。

一个 XML 实例文档可能引用多个名称空间的元素名,这些名称空间定义在不同模式中。为了引用和简化名称空间的名字,同样要使用 xmlns 声明。我们使用 XML Schema 实例名称空间的 schemaLocation 属性指定文件的位置。要注意,该属性不同于上一个例子中 xsd 名称空间的同名属性 schemaLocation

清单 6:使用来自多个模式的多个名称空间的名字


<?xml version="1.0"?>
<ACC:rootElement xmlns:ACC='http://www.SampleStore.com/Account'
      xmlns:PART='http://www.PartnerStore.com/PartsCatalog'
      xmlns:xsi='http://www.w3.org/1999/XMLSchema-instance'
      xsi:schemaLocation='http://www.PartnerStore.com/PartsCatalog
                          http://www.ProductStandards.org/repository/alpha.xsd
                          http://www.SampleStore.com/Account
                          http://www.SampleStore.com/repository/schema1.xsd'>
<ACC:InvoiceNo>123456789</ACC:InvoiceNo>

图 2:清单 5 和清单 6 的名称空间
图 2:清单 5 和清单 6 的名称空间

定义元素
定义元素就是定义元素的名字和内容模型。在 XML Schema 中,元素的内容模型由其类型定义,因此 XML 文档中实例元素的值必须符合模式中定义的类型。

简单类型

XML Schema 规范定义了一些值的简单类型,如 表 2:“预定义的值简单类型”所示。

类型包括简单类型和复杂类型。简单类型的值不能包含元素或属性。复杂类型可以产生在其他元素中嵌套元素的效果,或者为元素增加属性。(到目前为止本文中的例子都是用户定义的简单类型,比如 ProductCode)。XML Schema 规范也包括预定义的简单类型(请参阅侧栏 简单类型)。派生的简单类型 约束了基类型的值。比如,派生简单类型 ProductCode 的值是基类型 string 值的子集。

简单的、非嵌套的元素是简单类型
不含属性或其他元素的元素可以定义为简单类型,无论是预定义的简单类型还是用户定义的简单类型,如 stringintegerdecimaltimeProductCode 等等。

清单 7:一些元素的简单类型


<element name='age' type='integer'/>
<element name='price' type='decimal'/>

带有属性的元素必须是复杂类型
现在,试着向 清单 7 中的简单元素 price 增加属性 currency。您不能这样做,因为简单类型的元素不能有属性。如果希望增加属性,您必须把 price 元素定义成复杂类型。在 清单 8 的例子中,我们定义了一个 匿名类型,没有明确地命名这个复杂类型。换句话说,没有定义复杂类型 complexTypename 属性。

清单 8:一个复杂元素类型


<element name='price'>
  <complexType base='decimal' derivedBy='extension'>
    <attribute name='currency' type='string'/>
  </complexType>
</element>
<!-- In XML instance document, we can write: <price currency='US'>45.50</price> -->

嵌入其他元素的元素必须是复杂类型
在 XML 文档中,一个元素可能嵌入其他的元素。这种要求可以在 DTD 中直接表示。但 XML Schema 定义一个元素,这个元素有一个类型,而这个类型可以包含其他元素和属性的声明。表 1 给出了一个简单的例子。

表 1:DTD 和 XML Schema 中复杂数据类型的比较

XML 文档


<Book>
   <Title>Cool XML<Title>
   <Author>Cool Guy</Author>
</Book>
DTD


<Book>
   <Title>Cool XML<Title>
   <Author>Cool Guy</Author>
</Book>
XML Schema


<Book>
   <Title>Cool XML<Title>
   <Author>Cool Guy</Author>
</Book>

<!ELEMENT Book (Title, Author)>
<!ELEMENT Title (#PCDATA)>
<!ELEMENT Author (#PCDATA)>


<element name='Book' type='BookType'/>
<complexType name='BookType'>
    <element name='Title' type='string'/>
    <element name='Author' type='string'/>
</complexType>

尽管 表 1 中的 XML 代码同时满足 DTD 与 XML Schema 片段,但两者之间有一个很大的区别。在 DTD 中所有的元素都是全局性的,而表中的 XML Schema 允许把 TitleAuthor 定义成局部的——只出现在元素 Book 中。为了在 XML Schema 中实现与 DTD 声明完全相同的效果,元素 TitleAuthor 必须是全局范围的,如 清单 9 中所示。元素 elementref 属性使您能够引用前面声明的元素。

清单 9:用全局简单类型定义的复杂类型


<element name='Title' type='string'/>
<element name='Author' type='string'/>
<element name='Book' type='BookType'/>
<complexType name='BookType'>
   <element ref='Title'/>
   <element ref='Author'/>
</complexType>

表 1清单 9 所示的例子中, BookType 是全局性的,可用于声明其他元素。相反,清单 10 将该类型局部地定义到元素 Book 中,而且定义成匿名元素。要注意,表 1 中的 XML 文档片段与表 1、清单 9清单 10 中三个模式片段都匹配。

清单 10:隐藏 BookType 作为本地类型


<element name='Title' type='string'/>
<element name='Author' type='string'/>
<element name='Book'>
   <complexType>
      <element ref='Title'/>
      <element ref='Author'/>
   </complexType>
</element>

表示元素的复杂约束
对于表示元素内容模型的约束,XML Schema 比 DTD 提供了更大的灵活性。在最简单的层次上,像在 DTD 中那样,您可以把属性和元素声明关联起来,指明能够出现的给定元素集合序列:只能出现 1 次(1)、出现 0 次或多次(*)或者出现 1 次或多次(+)。您还可以表示 XML Schema 中的其他约束,比方说使用 element 元素的 minOccursmaxOccurs 属性,以及 choicegroupall 元素。

清单 11:表示元素类型的约束


<element name='Title' type='string'/>
<element name='Author' type='string'/>
<element name='Book'>
  <complexType>
    <element ref='Title' minOccurs='0'/>
    <element ref='Author' maxOccurs='2'/>
  </complexType>
</element>

清单 11 中,BookTitle 的出现是可选的(类似 DTD 的 '?')。但是,清单 11 也说明 Book 元素中至少要有一个但不能超过两个作者。elementminOccursmaxOccurs 属性的默认值是 1。元素 choice 只允许它的一个子女出现在实例中。另外一个元素 all,表示这样的约束:组中的所有子元素可以同时出现一次,或者都不出现,它们可以按任意的顺序出现。清单 12 表示 TitleAuthor 两者必须同时出现(顺序任意)在 Book 中,或者都不出现。这种约束很难在 DTD 中表示。

清单 12:指出必须为元素定义所有的类型


<xsd:element name='Title' type='string'/>
<xsd:element name='Author' type='string'/>
<xsd:element name='Book'>
  <xsd:complexType>
    <xsd:all>
      <xsd:element ref='Tile'/>
      <xsd:element ref='Author'/>
    </xsd:all>
  </xsd:complexType>
</xsd:element>

更上层楼
我们已经讨论了在 XML Schema 中定义元素所需的最基本的概念,通过一些简单的例子使您领略到它的强大功能。还有一些更强大的机制:

  • XML Schema 对类型继承提供了广泛的支持,允许重用以前定义的结构。使用所谓的 facets,您可以派生新的类型,表示其他某个类型值的更小子集,比如通过枚举、范围或模式匹配来定义子集。在本文的例子中,ProductCode 类型就是使用模式面( pattern facet)定义的。子类型也可以向基类型增加更多的元素和属性声明。
  • 有几种机制控制能否定义子类型,或者能否在具体的文档中替换为子类型。比如,有可能表示 InvoiceType ( Invoice 编号的类型)不允许子类型化,任何人都不能定义新版本的 InvoiceType。通过规定在特定的上下文中不能用 ProductCode 类型的子类型替换,也能表达这种约束。
  • 除了子类型外,还可以定义等价的类型,这样,一个类型的值可以用另一个类型代替。
  • 通过声明抽象的元素或者类型,XML Schema 提供了一种强制替换机制。
  • 为了方便起见,可以定义并命名属性组和元素组,从而能够在后面引用这些组达到重用的目的。
  • XML Schema 提供了三个元素——appInfodocumentationannotation——为模式作注解,以方便读者(documentation)和应用程序(appInfo)。
  • 基于子元素的某些属性可以表示惟一性约束。

可以通过 W3C 站点(请参阅 参考资料)的文档进一步研究 XML Schema,或者访问 dW XML 专区了解更多的内容。目前,XML Schema 规范已经被批准,并成为候选推荐标准(Candidate Recommendation),毫无疑问您将越来越多地用到它。

参考资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
[实验目的] 1、学习如何使用XMLSPY集成开发环境完成XML Schema相关的开发工作。 2、掌握XML Schema与DTD之间的区别,能够完成两者之间的转换;掌握在XML Schema中如何定义元素和属性,如何使用限制、列表和合并派生自己的简单数据类型,如何定义复杂数据类型,全局/局部元素和数据类型之间的区别;如何将XML Schema文档关联到XML实例数据文档,并完成文档的有效性验证。 3、掌握如何准确定义数据之间的参照完整性约束,如何在模式中使用多态性支持,如何在文档定义空值等等。 [实验内容和步骤] 1、使用XMLSPY集成开发环境,新建XML Schema文档,在各种不同的编辑视图中尝试采用不同的方式完成XML Schema文档的编辑和查看;并使用XMLSPY提供的便利,建立XMLSchema两者之间的关联,进行XML文档的良构以及有效性验证。 2、严格按照下图给出的文档模型,在XML Schema编辑环境的Schema视图中完成book.xsd的编写(不要使用Text视图进行编写): 在上图中,没有指定简单类型元素和属性的数据类型,请根据合理的情况,完成数据类型的创建(至少使用到限制方式中的三种以上的限制方面),请在IDE的Details视图->type和Facets中完成上述任务。 在上图中,有三个title元素分别表示book、section和figure的标题,请定义下述类型: titleType:1-100个字符的文本; bookTitleType:titleType类型限制派生的子类型,要求取枚举值“Data On the Web”、“TCP/IP Illustrated”等; sectionTitleType:titleType类型限制派生的子类型,要求必须形如“1.xxxx”、“1-1.xxxx”等等(表示第一节、第一节下面的第一节等等,注意section是递归的形式); figureTitleType:titleType类型限制派生的子类型,要求必须形如“1-1.xxxx” 、“1-1-1.xxxx”(表示第一节中的第一个图、第一节下面的第一节的第一个图等等); 然后编写book.xml,并使用多态性(即所有title的类型均为titleType,而数据实例中指明具体类型),请确保通过文档有效性验证。 3、在上次的DTD实验中,我们编写了SpyBase1.xml、SpyBase2.xml、以及SpyBase1.dtd和SpyBase2.dtd,这次需要完成SpyBase1.xsd和SpyBase2.xsd,建立模式与数据之间的关联,并进行文档有效性验证。在编写的XSD文档SpyBase1.xsd中,要求使用key/keyref描述数据的实体完整性以及数据之间的参照完整性(SpyBase2.xml不需要,因为已经使用嵌套消除了参照关系)。 [实验思考] 与ID/IDREF相比,key/keyref有哪些优点,在使用上有何不同? 假设SpyBase1.xml中的alias、mission、spy来自不同的命名空间中,如何在Schema中对其进行限定,请在XMLSPY中完成相应的xsd文档?修改SpyBase1.xml,并验证新的SpyBase1_2.xsd是否正确? [提交时间及内容] 最后提交时间 2013年?月?日 提交内容 提交book.xsd、book.xml使用多态)。 提交SpyBase1. xsd、SpyBase2. xsd。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值