新しい XML スキーマ システムは、DTD の制限 (補足記事「DTD の制限」を参照) を克服し、XML ドキュメントに豊富な文法構造を提供することを目的として、W3C 推奨標準になろうとしています。この記事では、スキーマの柔軟性を示し、XML スキーマ システムを使用して XML ドキュメントの最も基本的な構成要素である要素を定義する方法を説明します。
XML スキーマは DTD よりも強力です。 XML スキーマ メカニズムの威力を説明するために、次の 3 つのプログラム リストでは、要素を表現するさまざまな方法を簡単に比較しています。 リスト 1 は XML ドキュメント セグメントを示し、リスト 2 は DTD 構文を使用してこれら 2 つの要素を宣言し、リスト 3 は対応する XML スキーマ構文形式を示します。リスト 3 でも同じ XML 構文が使用されていることに注意してください。スキーマを通じて、検証パーサーは要素 InvoiceNo が正の整数であるかどうか、また ProductID 要素の最初の文字が A から Z までの文字とそれに続く 6 桁のアラビア数字であるかどうかをチェックできます。対照的に、DTD を参照する検証パーサーは、要素が文字列として表現されているかどうかをチェックすることしかできません。 リスト 1: XML ドキュメント セグメント<InvoiceNo>123456789</InvoiceNo> <ProductID>J123456</ProductID>
<!ELEMENT InvoiceNo (#PCDATA)> <!ELEMENT ProductID (#PCDATA)>
<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 スキーマは、要素名、型名、属性名、属性グループ名などの新しい名前のセットを定義します。これらの名前の定義と宣言はスキーマに書き込まれます。 リスト 3 では、InvoiceNo、ProductID、ProductCode などの名前を定義しています。 スキーマで定義された名前は、そのターゲット名前空間に属すると言います。ネームスペース自体には固定ですが制限のない名前があり、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>
<!--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中多了一个名称空间引用: www.PartnerStore.com/PartsCatalog 。这个名称空间不同于 targetNamespace 和标准名称空间。因此必须使用 import 声明元素引入,该元素的 schemaLocation 属性指明包含模式的文件位置。默认的名称空间是www.w3.org/1999/XMLSchema ,它的 xmlns 声明没有名字。每个非限定的名字如 schema 和 element ,都属于默认名称空间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 的名称空间
定义元素
定义元素就是定义元素的名字和内容模型。在 XML Schema 中,元素的内容模型由其类型定义,因此 XML 文档中实例元素的值必须符合模式中定义的类型。
类型包括简单类型和复杂类型。简单类型的值不能包含元素或属性。复杂类型可以产生在其他元素中嵌套元素的效果,或者为元素增加属性。(到目前为止本文中的例子都是用户定义的简单类型,比如 ProductCode )。XML Schema 规范也包括预定义的简单类型(请参阅侧栏 简单类型)。 派生的简单类型约束了基类型的值。比如,派生简单类型 ProductCode 的值是基类型 string 值的子集。
简单的、非嵌套的元素是简单类型
不含属性或其他元素的元素可以定义为简单类型,无论是预定义的简单类型还是用户定义的简单类型,如 string 、 integer 、 decimal 、 time 、 ProductCode 等等。
清单 7:一些元素的简单类型
<element name='age' type='integer'/> <element name='price' type='decimal'/>
带有属性的元素必须是复杂类型
现在,试着向 清单 7中的简单元素 price 增加属性 currency 。您不能这样做,因为简单类型的元素不能有属性。如果希望增加属性,您必须把 price 元素定义成复杂类型。在 清单 8的例子中,我们定义了一个 匿名类型,没有明确地命名这个复杂类型。换句话说,没有定义复杂类型 complexType 的 name 属性。
清单 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>
尽管 表 1中的 XML 代码同时满足 DTD 与 XML Schema 段,但两者之间有一个很大的区别。在 DTD 中所有的元素都是全局性的,而表中的 XML Schema 允许把 Title 和 Author 定义成局部的——只出现在元素 Book 中。为了在 XML Schema 中实现与 DTD 声明完全相同的效果,元素 Title 和 Author 必须是全局范围的,如 清单 9中所示。元素 element 的 ref 属性使您能够引用前面声明的元素。
清单 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 元素的 minOccurs 和 maxOccurs 属性,以及 choice 、 group 和 all 元素。
清单 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中, Book 中 Title 的出现是可选的(类似 DTD 的 '?')。但是, 清单 11也说明 Book 元素中至少要有一个但不能超过两个作者。 element 的 minOccurs 和 maxOccurs 属性的默认值是 1。元素 choice 只允许它的一个子女出现在实例中。另外一个元素 all ,表示这样的约束:组中的所有子元素可以同时出现一次,或者都不出现,它们可以按任意的顺序出现。 清单 12表示 Title 和 Author 两者必须同时出现(顺序任意)在 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 提供了三个元素—— appInfo 、 documentation 和 annotation ——为模式作注解,以方便读者( documentation )和应用程序( appInfo )。
基于子元素的某些属性可以表示惟一性约束。
可以通过 W3C 站点(请参阅 参考资料)的文档进一步研究 XML Schema,或者访问 dW XML 专区了解更多的内容。目前,XML Schema 规范已经被批准,并成为候选推荐标准(Candidate Recommendation),毫无疑问您将越来越多地用到它。
以上がXML Schemaを使って要素(画像やテキスト)を定義するための基礎知識を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。