Lược đồ XML 1.1, Phần 3: Nhập môn Lược đồ XML 1.1

Tiến triển lược đồ của bạn với hỗ trợ mạnh cho thẻ đại diện

Một mục tiêu thường xuyên của các tác giả lược đồ là xây dựng các lược đồ để có khả năng mở rộng, ở đây các thẻ đại diện (wildcard) đóng vai trò chủ chốt trong việc cung cấp các điểm có tính mở rộng. Các tính năng mới của thẻ đại diện được đưa vào trong Lược đồ XML 1.1 tạo điều kiện dễ dàng hơn cho các tác giả viết các lược đồ mở rộng được, có thể dung thứ các thay đổi trong tương lai. Trong phần thứ ba của loạt bài sáu phần này, các tác giả Neil Delima, Sandy Gao, Michael Glavassevich, và Khaled Noaman đã xem xét sâu sắc các tính năng phiên bản mà Lược đồ XML 1.1 đưa ra, cụ thể là các cơ chế thẻ đại diện và nội dung mở mới và mạnh mẽ.

Neil Delima, Phát triển phần mềm, EMC

Neil Delima là nhân viên phát triển phần mềm của IBM tại phòng thí nghiệm Toronto. Là một thành viên của nhóm phát triển trình phân tích XML Parser, Neil đã làm việc với nhiệm vụ phát triển và kiểm tra công nghệ XML trong hơn 7 năm qua. Neil là thành viên của hội đồng kiểm duyệt dự án trình phân tích Apache’s Xerces – Java Parser và góp phần xây dựng các bộ kiểm tra cho W3C DOM và XML 1.1



Sandy Gao, Phát triển phần mềm, EMC

Sandy (Shudi) Gao là nhân viên phát triển phần mềm của IBM tại Toronto. Sandy đã là thành viên của hội đồng kiểm duyệt dự án trình phân tích Apache’s Xerces – Java Parser từ năm 2001 và là người đóng góp chủ chốt tới hỗ trợ lược đồ XML. Sandy đại diện IBM tham gia nhóm làm việc phát triển lược đồ XML của W3C từ năm 2003. Sandy đóng góp chính cho sự phát triển lược đồ XML 1.1 và trở thành chủ biên của đặc tả trong năm 2006. Sandy cũng đại diện IBM trong nhóm W3C SML Working Group



Michael Glavassevich, Phát triển phần mềm, EMC

Michael Glavassevich thành viên của nhóm XML Parser Development (phát triển trình phân tích XML) tại phòng thí nghiệm của IBM Toronto và là một trong những người có đóng góp to lớn đối dự án Apache Xerces2 trong 5 năm vừa qua, ngoài ra anh còn tham gia xây dựng Lược đồ XML, XInclude, JAXP 1.3/1.4 và DOM Level 3. Michael cũng là đại diện của của IBM trong nhóm chuyên gia JAXP đã xây dựng JAXP 1.4



20 11 2009 (Xuất bản lần đầu tiên vào ngày 10 11 2010)

20/11/2009: Được cập nhật theo yêu cầu của tác giả: Dưới tiêu đề Nội dung mở ở mức tài liệu lược đồ trong đoạn 4, câu 2, đã thay đổi chuỗi ký tự "A value of mode indicates..." to "A value of none indicates..." (“Một giá trị của mode biểu thị...” thành “Một giá trị của none biểu thị...”)

Giới thiệu

Trong Hội thảo W3C về các trải nghiệm của người sử dụng lược đồ XML 1.0 (xem phần Tài nguyên), việc tương thích phiên bản lược đồ là một trong những mối quan tâm lớn của những người sử dụng lược đồ. Khi dữ liệu XML thay đổi, các lược đồ tương ứng cũng cần thay đổi theo. Bạn làm cách nào đảm bảo một mức tương thích để giảm bớt các đứt gãy cho các ứng dụng?

Các từ viết tắt thường dùng

  • URI: Mã nhận dạng Tài nguyên Đồng nhất
  • W3C: Tổ chức World Wide Web
  • XML: Ngôn ngữ Đánh dấu Mở rộng

Người ta thường nói về hai loại tương thích. Trong bối cảnh tương thích phiên bản lược đồ, tính tương thích lùi đòi hỏi rằng các cá thể hợp lệ với phiên bản lược đồ n vẫn còn hợp lệ dưới phiên bản lược đồ n+1. Đây là điều mà mọi người thường ghi nhớ trong đầu khi họ bàn về tính tương thích, và nó là sự tương thích dễ hỗ trợ hơn, vì các tác giả của phiên bản lược đồ n+1 có được cả lược đồ và các cá thể của phiên bản n.

Kiểu tương thích thứ hai là tính tương thích tiến, khi các cá thể hợp lệ với phiên bản lược đồ n+1 cũng hợp lệ dưới phiên bản lược đồ n. Điều này thường khó đạt được hơn, vì tác giả không biết được loại thay đổi nào có thể đưa ra trong phiên bản tiếp theo. Tất cả những gì bạn có thể làm là để lại các điểm mở rộng trong lược đồ để cho phép mở rộng trong tương lai.

Do tầm quan trọng và sự khó khăn trong việc đạt được tính tương thích tiến, một trong những mục tiêu chính trong Lược đồ XML 1.1 là làm cho nó dễ viết các lược đồ tương thích tiến. Các thẻ đại diện đóng một vai trò then chốt trong việc định nghĩa các điểm mở rộng trong lược đồ, và là trọng tâm của bài viết này. Bài tiếp theo trong loạt bài sẽ bàn luận các tính năng khác liên quan đến việc tương thích phiên bản lược đồ.

Nhóm công tác Lược đồ XML của W3C đã xuất bản một Hướng dẫn tương thích phiên bản dùng cho Lược đồ XML 1.1 (xem phần Tài nguyên). Những ai đang tìm sự giúp đỡ để tương thích phiên bản các lược đồ của họ cũng có thể nhận thấy nội dung của nó là đáng chú ý.

Các thẻ đại diện yếu

Các tác giả lược đồ, những người tạo ra một định nghĩa kiểu phức khi họ trộn một dãy các phần tử và thẻ đại diện chấp nhận cùng một vùng tên giống như là các phần tử khác có thể phát hiện ra rằng lược đồ mà họ đã viết là không hợp lệ. Lý do chắc chắn nhất của lỗi này là một sự vi phạm quy tắc UPA (Unique Particle Attribution - Gắn hạt duy nhất) định nghĩa trong Lược đồ XML 1.0 mà cơ bản là tuyên bố rằng các hạt (particle) khớp đúng (như, <xs:element> hay <xs:any> trong định nghĩa kiểu phức) có thể được xác định không lập lờ nước đôi cho từng phần tử trong cá thể tài liệu. Tính khả quyết này đơn giản hóa việc thực hiện các trình xác nhận hợp lệ và có thể hữu ích đối với các ứng dụng đòi hỏi một ánh xạ giữa các phần tử trong cá thể tài liệu với các hạt trong lược đồ. Nhưng nó cũng thách thức các tác giả lược đồ thể hiện một cách tự nhiên nội dung họ muốn cho phép.

Đoạn mã lược đồ trong Liệt kê 1 minh họa vấn đề mà các tác giả lược đồ thường gặp phải khi họ cố gắng tạo ra các điểm có tính mở rộng bằng cách sử dụng các thẻ đại diện. Hãy xét một kiểu phức hợp mô hình hoá bản ghi thắng-thua cho một đội thể thao. Trong một số môn thể thao như bóng đá Mỹ, các trận hoà là được phép. Trong các môn khác, chẳng hạn như bóng rổ, một trận đấu tiếp tục cho đến khi một bên được tuyên bố thắng cuộc. Một tác giả lược đồ có thể chọn ties (hoà) làm một phần tử tùy chọn (với minOccurs="0"). Còn có khả năng những con số thống kê kết quả khác có thể được đưa vào trong bản ghi kết quả của đội, ngoài thắng, thua, và hoà, do đó bạn có thể cần cho phép nội dung bổ sung thêm với một thẻ đại diện mà có thể được định nghĩa trong phiên bản tương lai của lược đồ.

Liệt kê 1. Đoạn mã lược đồ - Một định nghĩa kiểu bản ghi thắng-thua
<xs:complexType name="record">
  <xs:sequence>
    <xs:element name="wins" type="xs:nonNegativeInteger"/>
    <xs:element name="losses" type="xs:nonNegativeInteger"/>
    <xs:element name="ties" type="xs:nonNegativeInteger" minOccurs="0"/>
    <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="lax"/>
  </xs:sequence>
</xs:complexType>

Vấn đề của định nghĩa kiểu phức nói trên có thể được minh họa với cá thể tài liệu trong Liệt kê 2. Các phần tử wins (số trận thắng) và losses (số trận thua) trong tài liệu này khớp với các khai báo phần tử của chúng trong lược đồ (xem Liệt kê 1). Khi bạn định thử ánh xạ phần tử ties (số trận hoà) trở lại kiểu phức, bạn thấy rằng hai lựa chọn cho hạt này đều có thể khớp được. Có thể hoặc là khai báo phần tử ties (là tùy chọn) hoặc là thẻ đại diện cũng cho phép ties xuất hiện trong cá thể tài liệu. Vì lược đồ này có hơn một ánh xạ tiềm năng, nó vi phạm quy tắc UPA trong Lược đồ XML 1.0 và như vậy là không hợp lệ.

Liệt kê 2. Đoạn mã XML – Một phần tử bản ghi thắng-thua không hợp lệ
<record>
  <wins>20</wins>
  <losses>15</losses>
  <ties>8</ties>
  <points>48</points>
</record>

Như một cách tránh vấn đề này, tác giả lược đồ có thể đặt một phần tử bắt buộc phải có (required) vào giữa tùy chọn và thẻ đại diện như trong Liệt kê 3. Do phần tử separator (dấu phân tách) phải xuất hiện trong cá thể tài liệu, không có một sự lập lờ nào giữa nội dung khớp với khai báo phần tử separator và thẻ đại diện theo sau nó.

Liệt kê 3. Đoạn mã lược đồ - Định nghĩa một phần tử bắt buộc phải có giữa phần tử tùy chọn và thẻ đại diện tùy chọn
<xs:complexType name="record">
  <xs:sequence>
    <xs:element name="wins" type="xs:nonNegativeInteger"/>
    <xs:element name="losses" type="xs:nonNegativeInteger"/>
    <xs:element name="ties" type="xs:nonNegativeInteger" minOccurs="0"/>
    <xs:element name="separator"/>
    <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="lax"/>
  </xs:sequence>
</xs:complexType>

Mặc dù bạn thường có thể bổ sung một phần tử bắt buộc phải có để tránh lỗi UPA, nội dung được đưa vào các cá thể tài liệu thường vô nghĩa hoặc ép buộc một sự sắp đặt dữ liệu không tự nhiên. Hãy xem Liệt kê 4. Phần tử separator được đưa vào thêm không đóng góp được thông tin nào cho tài liệu nhưng phải ở đó để tài liệu hợp lệ. Lý tưởng là bạn không muốn một phần tử như vậy là một phần của tài liệu.

Liệt kê 4. Đoạn mã XML - Một phần tử bản ghi thắng-thua hợp lệ
<record>
  <wins>20</wins>
  <losses>15</losses>
  <ties>8</ties>
  <separator/>
  <points>48</points>
</record>

Để tạo điều kiện dễ dàng hơn cho các tác giả lược đồ khi tạo các mô hình nội dung tự nhiên hơn, Lược đồ XML 1.1 đã đưa ra khái niệm về một thẻ đại diện yếu. Thẻ đại diện yếu là một sự nới lỏng của quy tắc UPA giải quyết sự tranh chấp giữa một khai báo phần tử và thẻ đại diện bằng cách tuyên bố rằng khai báo phần tử luôn ưu tiên hơn thẻ đại diện. Kết quả là định nghĩa kiểu phức ở Liệt kê 1 trở thành hợp lệ trong Lược đồ XML 1.1 vì sự lập lờ giữa khai báo phần tử và thẻ đại diện không còn nữa. Lý do thẻ đại diện được bổ sung vào vị trí đầu tiên là để cho phép sự tiến hóa của lược đồ. Hãy tưởng tượng rằng tại lúc nào đó trong tương lai chúng ta cập nhật định nghĩa của kiểu record (bản ghi) để đưa thêm vào một phần tử points như trong Liệt kê 5. Bây giờ phần tử points trong thí dụ ở Liệt kê 2 đã được định nghĩa và vì quy tắc thẻ đại diện yếu nên rõ ràng nó khớp với khai báo phần tử của nó một cách không lập lờ.

Liệt kê 5. Đoạn mã lược đồ - Một định nghĩa kiểu bản ghi thắng-thua mở rộng
<xs:complexType name="record">
  <xs:sequence>
    <xs:element name="wins" type="xs:nonNegativeInteger"/>
    <xs:element name="losses" type="xs:nonNegativeInteger"/>
    <xs:element name="ties" type="xs:nonNegativeInteger" minOccurs="0"/>
    <xs:element name="points" type="xs:nonNegativeInteger" minOccurs="0"/>
    <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="lax"/>
  </xs:sequence>
</xs:complexType>

Các thẻ đại diện phủ định

Đôi khi người ta mong muốn rằng một thẻ đại diện không được khớp với các tên nào đó. Thí dụ, trong Lược đồ 1.0, ##other có thể được xác định là giá trị của thuộc tính namespace (không gian tên) trên một thẻ đại diện (<any> hoặc <anyAttribute>), biểu thị rằng thẻ đại diện này khớp với các vùng tên trong số các vùng tên trừ vùng tên đích của tài liệu lược đồ đang xét. Đặc tính này đã tỏ ra rất hữu ích trong việc để lại các điểm mở rộng trong các lược đồ.

Nhưng có một số kịch bản mà ##other không thể đáp ứng được. Lược đồ XML 1.1 đã đưa vào thêm một vài cơ chế để xác định các ngoại lệ cho các thẻ đại diện. Chúng có thể được gọi chung là các thẻ đại diện phủ định.

Loại trừ vùng tên

##other chỉ có thể sử dụng để loại trừ một vùng tên duy nhất, đó là vùng tên đích. Điều gì xảy ra nếu bạn muốn loại ra hơn một vùng tên? Thí dụ, nếu phiên bản 1 của một lược đồ sử dụng vùng tên đích ".../V1", và phiên bản 2 của lược đồ sử dụng ".../V2". Tác giả có thể mong muốn để lại các điểm mở rộng để chấp nhận các tên trong bất kỳ vùng tên nào trừ những thứ trong vùng tên của phiên bản 1 hoặc phiên bản 2. Liệt kê 6 cho thấy cách bây giờ bạn có thể thể hiện việc này trong Lược đồ XML 1.1.

Liệt kê 6. Đoạn mã lược đồ - Loại trừ vùng tên trong Lược đồ XML 1.1
<xs:complexType>
  <xs:sequence>
    ...
    <xs:any notNamespace="http://example.com/V1 http://example.com/V2"
            processContents="lax"/>
  </xs:sequence>
</xs:complexType>

Với thuộc tính mới notNamespace này, bạn có thể định rõ các vùng tên mà thẻ đại diện không khớp được. Nó có ý nghĩa ngược lại với thuộc tính namespace. Rõ ràng là chỉ một trong hai thuộc tính này là cần trên một thẻ đại diện.

Thuộc tính notNamespace nhận giá trị là một danh sách bất kỳ các giá trị URI nào phân cách bằng khoảng trống. Tương tự như thuộc tính namespace, notNamespace cũng cho phép các ký hiệu đặc biệt ##targetNamespace##local trong danh sách giá trị, biểu thị vùng tên đích và vùng tên rỗng tương ứng.

Loại trừ QName

Các thẻ đại diện thường được sử dụng để khớp các tên khác với các tên đã xác định rõ ràng. Liệt kê 7 cho thấy một thí dụ về một trường hợp như vậy.

Liệt kê 7. Đoạn mã lược đồ - Các thẻ đại diện khớp với các tên khác với các tên đã xác định rõ ràng
<xs:complexType name="referenceType">
  <xs:sequence>
    <xs:element ref="tns:uri"/>
    <xs:element ref="tns:description" minOccurs="0"/>
    <xs:any processContents="lax"
            minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

Mỗi kiểu reference đòi hỏi một phần tử con uri và một phần tử con description tùy chọn, theo sau là bất kỳ số lượng phần tử con nào dành cho các mở rộng. Cách làm này dường như ổn; nhưng không may là nó cũng cho phép các trường hợp sau đây (Liệt kê 8):

Liệt kê 8. Đoạn mã XML - Một phần tử reference với nhiều phần tử con uri
<reference>
  <uri>...</uri>
  <uri>...</uri>
</reference>

Bây giờ ứng dụng xử lý phần tử reference sẽ gặp khó khăn khi quyết định phần tử con uri nào được sử dụng. Đây là vì thẻ đại diện khớp với nhiều tên hơn dự định. Để khắc phục lỗi này, bạn có thể sử dụng khái niệm mới là các tên không được phép đã đưa vào Lược đồ XML 1.1, như trong Liệt kê 9.

Liệt kê 9. Đoạn mã lược đồ - Sử dụng các tên không cho phép
<xs:complexType name="referenceType">
  <xs:sequence>
    <xs:element ref="tns:uri"/>
    <xs:element ref="tns:description minOccurs="0"/>
    <xs:any processContents="lax" notQName="tns:uri"
            minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

Với thuộc tính notQName tác giả lược đồ có thể cung cấp một danh sách các QName mà thẻ đại diện không khớp được. Định nghĩa kiểu cập nhật này cấm thí dụ nói trên với hai phần tử con uri.

Loại trừ các phần tử anh chị em đã biết

Đôi khi tác giả lược đồ có thể mong muốn loại trừ một danh sách dài các tên, làm cho khó sử dụng thuộc tính notQName vì phải chỉ rõ tất cả các tên đó. Lược đồ XML 1.1 định rõ hai trường hợp có thể rất thường xảy ra, và cung cấp các cơ chế để đơn giản hóa chúng.

Nếu bạn định nghĩa một kiểu phức mô tả một người, sẽ có nhiều phần tử nằm trong kiểu này, dành cho tên, ngày sinh, địa chỉ, nghề nghiệp, v.v.... Nếu bạn cũng muốn sử dụng thẻ đại diện (hoặc một nội dung mở) để cho phép thông tin bổ sung được thêm vào, thì bạn cần giới hạn thẻ đại diện đó để không khớp được với các phần tử đã khai báo trong kiểu phức.

Để thực hiện điều này, hãy sử dụng thuộc tính notQName và liệt kê toàn bộ các tên phần tử đã biết. Không chỉ các danh sách loại trừ là rất dài, nó cũng sẽ khó bảo trì. Nếu một phần tử mới bổ sung vào kiểu này, bạn phải nhớ thêm tên của nó vào notQName. Trong Lược đồ XML 1.1, phép loại trừ như vậy có thể được mô tả dễ dàng bằng cách sử dụng ##definedSibling (Liệt kê 10):

Liệt kê 10. Đoạn mã lược đồ - Loại trừ QName bằng cách sử dụng ##definedSibling
<xs:complexType name="personType">
  <xs:sequence>
    <xs:element ref="tns:name"/>
    <xs:element ref="tns:dateOfBirth"/>
    <xs:element ref="tns:address"/>
    <xs:element ref="tns:occupation"/>
    <xs:any processContents="lax" notQName="##definedSibling"
            minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

Bạn có thể dùng từ khóa ##definedSibling như một giá trị trong thuộc tính notQName để biểu thị rằng thẻ đại diện đó không khớp với bất kỳ tên phần tử nào mà trước đó đã khai báo tường minh trong kiểu phức chứa chúng. Đây gồm có các phần tử được kế thừa (thông qua phần mở rộng) từ kiểu cơ sở.

Chú ý là ##definedSibling không áp dụng cho các thẻ đại diện thuộc tính (<anyAttribute>), vì XML không cho phép các thuộc tính cùng tên xuất hiện trên một phần tử.

Loại trừ những thứ toàn cục đã biết (known globals)

Nếu trong các phiên bản tương lai của một lược đồ được chờ đợi là sẽ đưa ra các khái niệm mới (do đó có các phần tử hoặc thuộc tính mới) trong vùng tên đích hiện tại, thì điều quan trọng là phải có các thẻ đại diện hoặc các nội dung mở ở các kiểu phức sẽ cho phép các tên mới. Đồng thời, các thẻ đại diện không được cho phép các khái niệm đã biết từ trước đối với phiên bản hiện tại của lược đồ. Vì nếu không, chúng đã được gộp trong các định nghĩa kiểu phức rồi.

Lấy ví dụ personType trong Liệt kê 10 trên đây. Nếu có một khai báo phần tử toàn cục cho person, vì có thẻ đại diện nên đoạn mã xml sau đây (Liệt kê 11) là hợp lệ đối với kiểu personType:

Liệt kê 11. Đoạn mã XML - Một phần tử person
<person>
  <name>...</name>
  <dateOfBirth>...</dateOfBirth>
  <address>...</address>
  <occupation>...</occupation>
  <person>...</person>
</person>

Để tránh điều này, Lược đồ XML 1.1 cung cấp một từ khóa đặc biệt nữa để sử dụng trong thuộc tính notQName, ##defined để biểu thị rằng thẻ đại diện này không khớp với bất kỳ tên nào mà đã có một khai báo toàn cục cho nó. Bạn có thể cập nhật thẻ đại diện trong kiểu phức personType như sau (Liệt kê 12):

Liệt kê 12. Đoạn mã lược đồ - Định nghĩa personType
<xs:complexType name="personType">
  <xs:sequence>
    ...
    <xs:any processContents="lax" notQName="##definedSibling ##defined"
            minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

Bây giờ nó sẽ không khớp được với cả các phần tử đã khai báo tường minh trong personType, lẫn với bất kỳ phần tử nào đã khai báo toàn cục. Kết quả là, cá thể tài liệu có một phần tử person xuất hiện trong phần tử person khác là không được phép.

Với điều kiện một phần tử toàn cục không được khai báo cho telephone, personType cập nhật sẽ cho phép một phần tử person như trong Liệt kê 13.

Liệt kê 13. Đoạn mã lược đồ - Một định nghĩa phần tử person bằng cách sử dụng phép loại trừ cái đã biết toàn cục
<person>
  <name>...</name>
  <dateOfBirth>...</dateOfBirth>
  <address>...</address>
  <occupation>...</occupation>
  <telephone>...</telephone>
</person>

Trong phiên bản tiếp theo của lược đồ, nếu một phần tử telephone được bổ sung vào thì cá thể tài liệu này trở nên không hợp lệ. Điều này là theo thiết kế, để phát tín hiệu rằng personType trong lược đồ mới thực sự cần được cập nhật để bao hàm cả telephone, nếu nó được mong chờ xuất hiện trong person.

Các nội dung mở

Trong Lược đồ XML 1.0, dãy các phần tử con được phép có trong một kiểu phức, hoàn toàn được xác định bởi mô hình nội dung của nó — các khai báo phần tử và thẻ đại diện được tổ chức trong các nhóm mô hình <sequence>, <choice>, và <all>. Lược đồ XML 1.1 đã mở rộng hơn nữa bằng cách cung cấp một cơ chế chấp nhận các phần tử con khác với những cái đã được định nghĩa rõ ràng trong mô hình nội dung. Cơ chế này thường được nói đến như là một nội dung mở. Để hiểu về nội dung mở, chúng ta hãy xem xét đoạn mã XML từ Liệt kê 14, đó là một minh hoạ về một mục CD đơn lẻ trong một catalô CD.

Liệt kê 14. Đoạn mã XML – Một mục CD trong một catalô CD
<cd id="0001">
  <artist>Foo Faa</artist>
  <album>Blah Blah</album>
  <genre>Alternative</genre>
  <price>11.99</price>
  <currency>USD</currency>
  <release_date>01-01-2009</release_date>
  <song>
    <track>XML XML</track>
    <duration>1.45</duration>
  </song>
</cd>

Bây giờ hãy xem một đoạn mã lược đồ (Liệt kê 15) mô tả phần tử cd một cách linh hoạt, và cho phép một tác giả lược đồ tăng thêm nội dung của phần tử cd mà không cần phải thay đổi lược đồ.

Liệt kê 15. Đoạn mã lược đồ - Định nghĩa mục CD
<xs:complexType name="CatalogEntry">
  <xs:sequence>
    <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
    <xs:element name="artist" type="xs:string"/>
    <xs:element name="album" type="xs:string"/>
    <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
    <xs:element name="price" type="xs:decimal"/>
    <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
    <xs:element name="release_date" type="xs:dateTime"/>
    <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
  <xs:attribute name="id" type="xs:string"/>
</xs:complexType>

<xs:element name="cd" type="tns:CatalogEntry"/>

Như bạn đã thấy từ lược đồ trong Liệt kê 15, các phần tử tùy chọn xuất hiện trong đoạn mã xml (Liệt kê 14) (cụ thể là genre, currency, và song) được định rõ trong lược đồ thông qua nhiều định nghĩa thẻ đại diện phần tử, <xs:any>, bị phân tán rải rác khắp định nghĩa kiểu phức, CatalogEntry. Điều này có thể làm cho lược đồ khó đọc và dẫn đến kết quả là thêm việc, đôi khi là trùng lặp vì đòi hỏi tác giả lược đồ chèn vào các khai báo thẻ đại diện trong lược đồ.

Nội dung mở nhằm giải quyết vấn đề này bằng cách cung cấp các thẻ đại diện mặc định, mở rộng mô hình nội dung để chấp nhận các phần tử ở bất cứ đâu hoặc chỉ ở phần cuối mô hình nội dung. Các nội dung mở có thể được xác định ở mức lược đồ hoặc ở mức kiểu phức. Chú ý là thẻ đại diện nội dung mở thậm chí còn yếu hơn so với các thẻ đại diện được xác định tường minh. Có nghĩa là, nếu một phần tử trong dãy phần tử con có thể khớp với hoặc một thẻ đại diện tường minh hoặc thẻ đại diện nội dung mở thì thẻ đại diện tường minh được ưu tiên.

Nội dung mở trong định nghĩa kiểu phức

Để xác định cụ thể nội dung mở cho một kiểu phức, hãy gồm thêm một phần tử con <xs:openContent> trong định nghĩa kiểu phức hoặc trong phần tử con <xs:restriction><xs:extension> của định nghĩa kiểu phức. Phần tử <xs:openContent> có thể chứa các thuộc tính tùy chọn idmode.

Giá trị của thuộc tính mode quyết định cách mà mô hình nội dung được mở rộng. Giá trị interleave biểu thị rằng các phần tử khớp với thẻ đại diện nội dung mở có thể chấp nhận được ở bất cứ đâu trong dãy phần tử con, ngược lại giá trị suffix biểu thị rằng các phần tử chỉ có thể được chấp nhận ở cuối dãy. Thuộc tính mode cũng có thể nhận giá trị none, chúng tôi sẽ bàn luận cụ thể hơn trong tiểu mục tiếp theo.

Phần tử con của phần tử <xs:openContent> là một thẻ đại diện phần tử.

Trong Liệt kê 16, chúng tôi minh họa cách định nghĩa phần tử cd bằng cách sử dụng đặc tính nội dung mở mới trong Lược đồ XML 1.1. Nó cho thấy cách bạn có thể thay thế các thẻ đại diện phần tử từ đoạn mã lược đồ trong Liệt kê 15 với một nội dung mở.

Liệt kê 16. Đoạn mã lược đồ - Một mục CD sử dụng nội dung mở
<xs:complexType name="CatalogEntry">
  <xs:openContent mode="interleave">
    <xs:any namespace="##any" processContents="skip"/>
  </xs:openContent>

  <xs:sequence>
    <xs:element name="artist" type="xs:string"/>
    <xs:element name="album" type="xs:string"/>
    <xs:element name="price" type="xs:decimal"/>
    <xs:element name="release_date" type="xs:dateTime"/>
  </xs:sequence>
  <xs:attribute name="id" type="xs:string"/>
</xs:complexType>

<xs:element name="cd" type="tns:CatalogEntry"/>

Trong Liệt kê 16, định nghĩa kiểu phức chứa một dãy bốn phần tử con được định nghĩa một cách tường minh. Ngoài ra, phần tử <xs:openContent> cho phép các phần tử từ bất kỳ vùng tên nào xuất hiện ở bất cứ đâu trong phạm vi các phần tử con.

Nội dung mở ở mức tài liệu lược đồ

Các tác giả lược đồ thường cần bổ sung cùng một loại thẻ đại diện vào một số lượng lớn các kiểu phức để cho phép mở rộng sau này. Điều này đòi hỏi khả năng xác định một nội dung mở mặc định áp dụng cho tất cả các kiểu phức. Nó làm giảm bớt nỗ lực viết và duy trì lược đồ, cũng như đảm bảo rằng không có kiểu phức nào vô tình thành không mở rộng được.

Để xác định nội dung mở mặc định, hãy gồm thêm một phần tử con <xs:defaultOpenContent> dưới phần tử <xs:schema>. Giống như phần tử <xs:openContent>, phần tử <xs:defaultOpenContent> chứa một thẻ đại diện phần tử và các thuộc tính tùy chọn idmode, ở đây mode nhận các giá trị interleave hoặc suffix.

Ngoài ra, phần tử nội dung mở mặc định có thể chứa một thuộc tính tùy chọn appliesToEmpty. Khi giá trị của thuộc tính appliesToEmptytrue, nội dung mở mặc định được áp dụng cho tất cả các kiểu phức trong tài liệu lược đồ hiện hành. Trái lại, giá trị false biểu thị rằng nội dung mở mặc định không được áp dụng nếu một kiểu phức có thể có một mô hình nội dung rỗng.

Một cách khác để đè lên hành vi mặc định là định rõ none như là giá trị của mode trong một phần tử <xs:openContent> của một kiểu phức. Một giá trị none biểu thị rằng kiểu phức này không sử dụng nội dung mở mặc định.

Trong Liệt kê 17, chúng tôi sửa đổi đoạn mã lược đồ từ Liệt kê 16 để sử dụng một nội dung mở mặc định thay vì một nội dung mở ở mức kiểu phức.

Liệt kê 17. Đoạn mã lược đồ - Một mục CD sử dụng nội dung mở mặc định
<xs:schema ...>
...
<xs:defaultOpenContent mode="interleave">
  <xs:any namespace="##any" processContents="skip"/>
</xs:openContent>
...
<xs:complexType name="CatalogEntry">
  <xs:sequence>
    <xs:element name="artist" type="xs:string"/>
    <xs:element name="album" type="xs:string"/>
    <xs:element name="price" type="xs:decimal"/>
    <xs:element name="release_date" type="xs:dateTime"/>
  </xs:sequence>
  <xs:attribute name="id" type="xs:string"/>
</xs:complexType>
<xs:element name="cd" type="tns:CatalogEntry"/>
...
</xs:schema>

Mô hình nội dung của định nghĩa kiểu phức, CatalogEntry, chứa một dãy bốn phần tử con được định nghĩa tường minh cũng như một nội dung mở được phép của phần tử <xs:defaultOpenContent> định nghĩa ở mức lược đồ.

Các thuộc tính trên toàn tài liệu lược đồ mặc định

Trong Lược đồ XML 1.0, các tác giả lược đồ có khả năng định nghĩa một tập hợp thông dụng các thuộc tính đối với một kiểu phức cho trước bằng cách sử dụng <xs:attributeGroup>. Liệt kê 18 cho thấy một thí dụ của một nhóm thuộc tính định nghĩa hai thuộc tính thường được sử dụng: widthheight.

Liệt kê 18. Đoạn mã lược đồ - Các thuộc tính thông dụng được định nghĩa bằng cách sử dụng một nhóm thuộc tính
<xs:attributeGroup name="dimensionGroup">
  <xs:attribute name="width" type="xs:int"/>
  <xs:attribute name="height" type="xs:int"/>
</xs:attributeGroup>

<xs:complexType name="dimensionType">
  ...
  <xs:attributeGroup ref="tns:dimensionGroup"/>
</xs:complexType>

Nếu tập hợp các thuộc tính này là chung cho nhiều định nghĩa kiểu phức, không có cách nào dễ dàng để biểu thị điều đó trong Lược đồ XML 1.0, ngoài cách gộp thêm vào một tham chiếu nhóm thuộc tính trong toàn bộ các định nghĩa kiểu phức. Liệt kê 19 minh họa, trong Lược đồ XML 1.0, cách mà nhiều định nghĩa kiểu phức có thể định nghĩa cùng một tập hợp các thuộc tính bằng cách tham chiếu cùng một nhóm thuộc tính.

Liệt kê 19. Đoạn mã lược đồ - Các thuộc tính thông dụng được định nghĩa trong nhiều định nghĩa kiểu phức
<xs:attributeGroup name="dimensionGroup">
  <xs:attribute name="width" type="xs:int"/>
  <xs:attribute name="height" type="xs:int"/>
</xs:attributeGroup>

<xs:complexType name="dimensionType">
  ...
  <xs:attributeGroup ref="tns:dimensionGroup"/>
</xs:complexType>

<xs:complexType name="sofa">
  ...
  <xs:attributeGroup ref="tns:dimensionGroup"/>
</xs:complexType>

Lược đồ XML 1.1 đã đưa ra khái niệm về nhóm thuộc tính mặc định. Trong phần tử <xs:schema> bạn có thể chỉ định một định nghĩa nhóm thuộc tính là mặc định (bằng cách sử dụng thuộc tính defaultAttributes). Định nghĩa nhóm thuộc tính này sẽ tự động được gộp vào từng kiểu phức được định nghĩa trong tài liệu lược đồ. Trong Liệt kê 20 dưới đây, cả dimensionTypesofa sẽ gộp các thuộc tính được định nghĩa vào nhóm thuộc tính dimensionGroup. Không cần phải tham chiếu một cách tường minh nhóm thuộc tính này trong cả hai định nghĩa kiểu phức ấy.

Liệt kê 20. Đoạn mã lược đồ - Các thuộc tính thông dụng được định nghĩa bằng cách sử dụng các thuộc tính mặc định
<xs:schema ....
           defaultAttributes="tns:dimensionGroup"/>

<xs:attributeGroup name="dimensionGroup">
  <xs:attribute name="width" type="xs:int"/>
  <xs:attribute name="height" type="xs:int"/>
</xs:attributeGroup>

<xs:complexType name="dimensionType">
  ...
</xs:complexType>

<xs:complexType name="sofa">
  ...
</xs:complexType>

...

</xs:schema>

Nếu một định nghĩa kiểu phức muốn đè lên hành vi mặc định (nghĩa là, bạn không muốn gộp thêm nhóm thuộc tính), bạn có thể đặt thuộc tính defaultAttributesApply của phần tử <xs:complexType>false. Trong Liệt kê 21, <xs:complexType> có tên person đè lên hành vi mặc định của các thuộc tính mặc định (bằng cách chỉ ra rằng bạn không muốn gộp thêm danh mục các thuộc tính mặc định).

Liệt kê 21. Đoạn mã lược đồ - Đè lên hành vi của các thuộc tính mặc định
<xs:schema ...
           defaultAttributes="tns:dimensionGroup"/>

<xs:attributeGroup name="dimensionGroup">
  <xs:attribute name="width" type="xs:int"/>
  <xs:attribute name="height" type="xs:int"/>
</xs:attributeGroup>

<xs:complexType name="dimensionType">
  ...
</xs:complexType>

<xs:complexType name="person" defaultAttributesApply="false">
  ...
</xs:complexType>

...

</xs:schema>

Các nhóm thuộc tính mặc định làm dễ dàng hơn việc xác định các thuộc tính mà mọi kiểu phức trong một lược đồ phải chấp nhận (thí dụ, xml:idxml:lang, hoặc một thẻ đại diện thuộc tính).

Kết luận

Trong bài này, chúng tôi đã bàn luận về một vài tính năng tương thích phiên bản trong Lược đồ XML 1.1, làm nổi bật các thay đổi về hỗ trợ thẻ đại diện và sự bổ sung nội dung mở cho phép các tác giả lược đồ XML viết ra các lược đồ có thể tương thích với các phiên bản trong tương lai. Trong Phần 4 của loạt bài này, chúng ta sẽ khám phá nhiều tính năng tương thích phiên bản hơn, chẳng hạn như việc gộp vào có điều kiện và đè lên thành phần

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=580270
ArticleTitle=Lược đồ XML 1.1, Phần 3: Nhập môn Lược đồ XML 1.1
publish-date=11202009