Определение типа со сложным телом
При определении сложного типа можно воспользоваться уже определенным, базовым, сложным типом, расширив его дополнительными элементами, или, наоборот, удалив из него некоторые элементы. Для этого необходимо применить компонент complexContent. В этом компоненте, так же как и в компоненте simpleContent, записывается либо компонент extension, если надо расширить базовый тип, либо компонент restriction, если нужно его сузить. Базовый тип указывается атрибутом base, так же как и при записи компонента simpleContent, но теперь это должен быть сложный, а не простой тип.
Расширим, например, определенный выше тип bookType, добавив год издания — элемент year:
<xsd:complexType name="newBookType">
<xsd:complexContent>
<xsd:extension base="bookType">
<xsd:sequence>
<xsd:element name="year" type="xsd:gYear">
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
При сужении базового типа компонентом restriction надо перечислить те элементы, которые останутся после сужения. Например, оставим в типе newbookType только автора и название книги из типа bookType:
<xsd:complexType name="newBookType">
<xsd:complexContent>
<xsd:restriction base="bookType">
<xsd:sequence>
<xsd:element name="author" type="xsd:normalizedString" minOccurs="0" />
<xsd:element name="title" type="xsd:normalizedString" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
Это описание выглядит странно. Почему надо заново объявлять все элементы, остающиеся после сужения? Не проще ли определить новый тип? Дело в том, что в язык XSD внесены элементы объектно-ориентированного программирования, которых мы не будем касаться. Расширенный и суженный типы связаны со своим базовым типом отношением наследования, и к ним можно применить операцию подстановки. У всех типов языка XSD есть общий предок — базовый тип anytype. От него наследуются все сложные типы. Это подобно тому, как у всех классов Java есть общий предок — класс object, а все массивы наследуются от него. От базового типа аnутуре наследуется и типanySimpleType — общий предок всех простых типов.
Таким образом, сложные типы определяются как сужение типа anytype. Если строго подходить к определению сложного типа, то определение типа bookType, сделанное в начале предыдущего раздела, надо записать так:
<xsd:complexType name="bookType">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence maxOccurs="unbounded">
<xsd:element name="author" type="xsd:normalizedString" minOccurs="0" />
<xsd:element name="title" type="xsd:normalizedString" />
<xsd:element name="pages" type="xsd:positiveInteger" minOccurs="0" />
<xsd:element name="publisher" type="xsd:normalizedString"minOccurs="0" />
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
Ниже в листинге 2 представлена XSD-схема для XML-документа из листинга 1.
<?xml version="1.0"?>
<notebook>
<person>
<name first="Иван" second="Петрович" surname="Сидоров" />
<birthday>25.03.1977</birthday>
<adress>
<street>Садовая, 23-15</street>
<city>Урюпинск</city>
<zip>123456</zip>
</adress>
<phone-list>
<work-phone>2654321</work-phone>
<work-phone>2654023</work-phone>
<home-phone>3456781</home-phone>
</phone-list>
</person>
<person>
<name first="Мария" second="Петровна" surname="Сидорова" />
<birthday>17.035.1969</birthday>
<adress>
<street>Ягодная, 17</street>
<city>Жмеринка</city>
<zip>234561</zip>
</adress>
<phone-list>
<work-phone></work-phone>
<work-phone></work-phone>
<home-phone>2334455</home-phone>
</phone-list>
</person>
</notebook>
Листинг 1
<?xml version="1.0"?>
<!-- Имя файла: AdressBook01.xsd -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="notebook" type="notebookType" />
<xsd:complexType name="notebookType">
<xsd:element name="person" type="personType" minOccurs="0" maxOccurs="unbounded" />
</xsd:complexType>
<xsd:complexType name="personType">
<xsd:sequence>
<xsd:element name="name">
<xsd:complexType>
<xsd:attribute name="first" type="xsd:string" use="optional" />
<xsd:attribute name="second" type="xsd:string" use="optional" />
<xsd:attribute name="surname" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
<xsd:element name="birthday" type="ruDate" minOccurs="0" />
<xsd:element name="address" type="addressType" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="phone-list" type="phone-listType" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="addressType" >
<xsd:sequence>
<xsd:element name="street" type="xsd:string" />
<xsd:element name="city" type="cityType" />
<xsd:element name="zip" type="xsd:positiveInteger" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name='cityType'>
<xsd:simpleContent>
<xsd:extension base='xsd:string' >
<xsd: attribute name='type' type='placeType' default='город' />
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="placeType">
<xsd:restriction base = "xsd:string">
<xsd:enumeration value="ropoд" />
<xsd:enumeration value="пoceлoк" />
<xsd:enumeration value="дepeвня" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="phone-listType">
<xsd:element name="work-phone" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="home-phone" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:complexType>
<xsd:simpleType name="ruDate">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{2}.[0-9]{2}.[0-9]{4}" />
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Листинг 2
Листинг 1.45, как обычный XML-документ, начинается с пролога, показывающего версию XML и определяющего стандартное пространство имен схемы XML с идентификатором http://www.w3.org/2001/XMLSchema. С этим идентификатором связан префикс xsd. Конечно, префикс может быть другим, часто пишут префикс xs.
Все описание схемы нашей адресной книжки заключено в третьей строке, в которой указано, что адресная книга состоит из одного элемента с именем notebook, имеющего сложный тип notebookType. Этот элемент должен появиться в документе ровно один раз. Остальная часть листинга 2 посвящена описанию типа этого элемента и других типов.
Определение сложного типа notebookType несложно. Оно занимает три строки листинга, не считая открывающего и закрывающего тега, и просто говорит о том, что данный тип составляют несколько элементов person типа personType.
Определение типа personType немногим сложнее. Оно означает, что этот тип составляют четыре элемента: name, birthday, address и phone-list. Для элемента name сразу же объявлены необязательные атрибуты first и second простого типа string, определенного в пространстве имен xsd. Тип обязательного атрибута surname — тоже string.
Далее в листинге 2 определяются оставшиеся типы addressType, phonelistType и ruDate. Необходимость определения простого типа ruDateвозникает потому, что встроенный в схему XML тип date предписывает записывать дату в виде 2003-02-22, а у нас принят формат 22.02.2003. Тип ruDate определяется как сужение (restriction) типа string с помощью шаблона. Шаблон (pattern) для записи даты в виде ДД.ММ.ГГГГ задается регулярным выражением.