Một ví dụ về XSD

Bài này sẽ hướng dẫn bạn cách viết một XML Schema. Bạn cũng sẽ học được các phương pháp khác nhau để viết schema.

Tài liệu XML

Hãy cùng xem tài liệu XML có tên là "shiporder.xml":

<?xml version="1.0" encoding="ISO-8859-1"?>
<shiporder orderid="889923">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="shiporder.xsd">
 <orderperson>George Bush</orderperson>
 <shipto>
  <name>John Adams</name>
  <address>Oxford Street</address>
  <city>London</city>
  <country>UK</country>
 </shipto>
 <item>
  <title>Empire Burlesque</title>
  <note>Special Edition</note>
  <quantity>1</quantity>
  <price>10.90</price>
 </item>
 <item>
  <title>Hide your heart</title>
  <quantity>1</quantity>
  <price>9.90</price>
 </item>
</shiporder>

Tài liệu XML trên bao gồm phần tử gốc "shiporder", chứa thuộc tính bắt buộc có tên "orderid". Phần tử "shiporder" chứa ba phần tử con khác nhau: "orderperson", "shipto" và "item". Phần tử "item" xuất hiện hai lần, nó chứa một phần tử "title", một phần tử tùy chọn "note", một phần tử "quantity" và một phần tử "price".

Đoạn này xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" thông báo cho bộ giải mã XML rằng cần phải kiểm tra tài liệu này theo một schema. Đoạn này: xsi:noNamespaceSchemaLocation="shiporder.xsd" quy định vị trí của schema (ở đây, nó nằm trong cùng thư mục với "shiporder.xml").

Tạo một XML Schema

Hiện tại, chúng ta cần tạo một schema cho tài liệu XML trên.

Chúng ta có thể bắt đầu bằng cách mở một tệp mới và đặt tên là "shiporder.xsd". Để tạo schema, chúng ta chỉ cần đơn giản tuân theo cấu trúc của tài liệu XML, định nghĩa mỗi phần tử mà chúng ta đã tìm thấy. Đầu tiên, chúng ta bắt đầu với một宣言 XML tiêu chuẩn:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...
...
</xs:schema>

Trong schema trên, chúng ta đã sử dụng không gian tên tiêu chuẩn (xs), không gian tên này liên quan đến ngôn ngữ định nghĩa Schema (Schema language definition), giá trị tiêu chuẩn là http://www.w3.org/2001/XMLSchema.

Tiếp theo, chúng ta cần định nghĩa phần tử "shiporder" là loại phức hợp. Phần tử này có một thuộc tính chứa các phần tử khác, vì vậy chúng ta xác định nó là loại phức hợp. Các phần tử con của phần tử "shiporder" được bao bọc bởi phần tử xs:sequence, định nghĩa thứ tự của các phần tử con:

<xs:element name="shiporder">
 <xs:complexType>
  <xs:sequence>
  ...
  ...
  </xs:sequence>
  ...
 </xs:complexType>
</xs:element>

Sau đó, chúng ta cần định nghĩa phần tử "orderperson" là loại đơn giản (vì nó không chứa bất kỳ thuộc tính hoặc phần tử nào khác). tiền tố của loại (xs:string) được quy định bởi tiền tố của không gian tên, không gian tên này liên quan đến XML schema chỉ định các loại dữ liệu schema được định nghĩa trước:

<xs:element name="orderperson" type="xs:string"/>

Tiếp theo, tôi cần định nghĩa hai phần tử là loại phức hợp: "shipto" và "item". Chúng ta bắt đầu từ việc định nghĩa phần tử "shipto":

<xs:element name="shipto">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="name" type="xs:string"/>
   <xs:element name="address" type="xs:string"/>
   <xs:element name="city" type="xs:string"/>
   <xs:element name="country" type="xs:string"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>

Bằng cách sử dụng schema, chúng ta có thể sử dụng thuộc tính maxOccurs và minOccurs để định nghĩa số lần xuất hiện của một phần tử. maxOccurs định nghĩa số lần xuất hiện tối đa của một phần tử, trong khi minOccurs định nghĩa số lần xuất hiện tối thiểu của một phần tử. Giá trị mặc định của maxOccurs và minOccurs đều là 1!

Hiện tại, chúng ta có thể định nghĩa "item" phần tử. Phần tử này có thể xuất hiện nhiều lần trong phần tử "shiporder". Điều này được thực hiện bằng cách đặt giá trị thuộc tính maxOccurs của phần tử "item" là "unbounded", như vậy phần tử "item" có thể xuất hiện nhiều lần theo ý muốn của tác giả. Lưu ý rằng phần tử "note" là phần tử tùy chọn. Chúng ta đã đặt thuộc tính minOccurs của phần tử này là 0:

<xs:element name="item" maxOccurs="unbounded">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="title" type="xs:string"/>
   <xs:element name="note" type="xs:string" minOccurs="0"/>
   <xs:element name="quantity" type="xs:positiveInteger"/>
   <xs:element name="price" type="xs:decimal"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>

Bây giờ, chúng ta có thể định nghĩa thuộc tính của phần tử "shiporder" rồi. Do đây là thuộc tính bắt buộc, chúng ta quy định use="required".

Ghi chú:Định nghĩa của thuộc tính này phải được đặt cuối cùng:

<xs:attribute name="orderid" type="xs:string" use="required"/>

Đây là danh sách tài liệu của tệp schema có tên "shiporder.xsd":

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="shiporder">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="orderperson" type="xs:string"/>
   <xs:element name="shipto">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="address" type="xs:string"/>
      <xs:element name="city" type="xs:string"/>
      <xs:element name="country" type="xs:string"/>
     </xs:sequence>
    </xs:complexType>
   </xs:element>
   <xs:element name="item" maxOccurs="unbounded">
    <xs:complexType>
     <xs:sequence>
      <xs:element name="title" type="xs:string"/>
      <xs:element name="note" type="xs:string" minOccurs="0"/>
      <xs:element name="quantity" type="xs:positiveInteger"/>
      <xs:element name="price" type="xs:decimal"/>
     </xs:sequence>
    </xs:complexType>
   </xs:element>
  </xs:sequence>
  <xs:attribute name="orderid" type="xs:string" use="required"/>
 </xs:complexType>
</xs:element>
</xs:schema>

Chia tách Schema

Phương pháp thiết kế trước rất dễ dàng, nhưng khi tài liệu phức tạp lại khó đọc và bảo trì.

Phương pháp thiết kế tiếp theo dựa trên việc định nghĩa tất cả các phần tử và thuộc tính trước, sau đó sử dụng thuộc tính ref để tham chiếu chúng.

Đây là tệp schema được thiết kế bằng phương pháp mới:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Định nghĩa của phần tử đơn giản -->
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
<!-- Định nghĩa của thuộc tính -->
<xs:attribute name="orderid" type="xs:string"/>
<!-- Định nghĩa của phần tử phức hợp -->
<xs:element name="shipto">
 <xs:complexType>
  <xs:sequence>
   <xs:element ref="name"/>
   <xs:element ref="address"/>
   <xs:element ref="city"/>
   <xs:element ref="country"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>
<xs:element name="item">
 <xs:complexType>
  <xs:sequence>
   <xs:element ref="title"/>
   <xs:element ref="note" minOccurs="0"/>
   <xs:element ref="quantity"/>
   <xs:element ref="price"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>
<xs:element name="shiporder">
 <xs:complexType>
  <xs:sequence>
   <xs:element ref="orderperson"/>
   <xs:element ref="shipto"/>
   <xs:element ref="item" maxOccurs="unbounded"/>
  </xs:sequence>
  <xs:attribute ref="orderid" use="required"/>
 </xs:complexType>
</xs:element>
</xs:schema>

Sử dụng loại đã chỉ định (Named Types)

Phương pháp thiết kế thứ ba định nghĩa lớp hoặc loại, từ đó chúng ta có khả năng tái sử dụng định nghĩa của phần tử. Cụ thể là: trước tiên đặt tên cho phần tử đơn giản và phức hợp, sau đó chỉ đến chúng thông qua thuộc tính type của phần tử.

Đây là tệp schema được thiết kế bằng phương pháp thứ ba ("shiporder.xsd"):

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="stringtype">
 <xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="inttype">
 <xs:restriction base="xs:positiveInteger"/>
</xs:simpleType>
<xs:simpleType name="dectype">
 <xs:restriction base="xs:decimal"/>
</xs:simpleType>
<xs:simpleType name="orderidtype">
 <xs:restriction base="xs:string">
  <xs:pattern value="[0-9]{6}"/>
 </xs:restriction>
</xs:simpleType>
<xs:complexType name="shiptotype">
 <xs:sequence>
  <xs:element name="name" type="stringtype"/>
  <xs:element name="address" type="stringtype"/>
  <xs:element name="city" type="stringtype"/>
  <xs:element name="country" type="stringtype"/>
 </xs:sequence>
</xs:complexType>
<xs:complexType name="itemtype">
 <xs:sequence>
  <xs:element name="title" type="stringtype"/>
  <xs:element name="note" type="stringtype" minOccurs="0"/>
  <xs:element name="quantity" type="inttype"/>
  <xs:element name="price" type="dectype"/>
 </xs:sequence>
</xs:complexType>
<xs:complexType name="shipordertype">
 <xs:sequence>
  <xs:element name="orderperson" type="stringtype"/>
  <xs:element name="shipto" type="shiptotype"/>
  <xs:element name="item" maxOccurs="unbounded" type="itemtype"/>
 </xs:sequence>
 <xs:attribute name="orderid" type="orderidtype" use="required"/>
</xs:complexType>
<xs:element name="shiporder" type="shipordertype"/>
</xs:schema>

element restriction cho thấy loại dữ liệu nguồn từ loại dữ liệu trong không gian tên W3C XML Schema. Do đó, đoạn sau cũng có nghĩa là giá trị của phần tử hoặc thuộc tính phải là giá trị loại chuỗi:

<xs:restriction base="xs:string">

element restriction thường được sử dụng để áp đặt các hạn chế lên phần tử. Hãy xem các đoạn sau này từ schema trên:

<xs:simpleType name="orderidtype">
 <xs:restriction base="xs:string">
  <xs:pattern value="[0-9]{6}"/>
 </xs:restriction>
</xs:simpleType>

Mã này chỉ ra rằng giá trị của yếu tố hoặc thuộc tính phải là chuỗi và phải là sáu ký tự liên tiếp, và các ký tự này phải là số từ 0 đến 9.