>>>

Проектирование, разработка и оптимизация веб-приложений

XML XML Schema Definition Language

Цель лабораторной работы:

  1. Познакомиться c XML схемами на примере XSD
  2. Научиться описывать структуру XML документов с помощью XSD

Теоретические сведения

Консорциум W3C выработал рекомендацию языка определения схем XML (XSD), объединив наиболее популярные языки описания схем в один стандарт. Основная цель, которая при этом преследовалась, — получение стандарта, который можно широко реализовать и при этом он платформно-независимый.

Язык XML Schema Definition Language, который также называют XML Schema Language, во многом похож на язык XDR, с которым вы познакомились раньше. Схемы XSD способны решать следующие задачи:

Корневым элементом в схеме XML является элемент Schema, который содержит все остальные элементы в документе схемы. В рамках корневого элемента схемы XSD атрибутом xmlns определяется пространство имен XMLSchema, которое содержит элементы и атрибуты XSD схемы.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Все элементы XSD начинаются с префикса xsd:, который указывается для пространства имен XSD, объявленного в корневом элементе экземпляра схемы.

XML-документ, который проверяется с помощью схемы, также должен содержать объявление пространства имен. Пространство имен всегда указывается в корневом элементе экземпляра документа с помощью атрибута xmlns:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

Это пространство имен содержит элементы и атрибуты XMLSchema, которые можно включать в документ XML. По общему соглашению префикс xsi используется для этого пространства имен и добавляется в начале имен всех элементов и атрибутов, принадлежащих пространству имен, отделяясь от них двоеточием.

Ссылка на конкретную схему приводится в атрибуте

xsi:schemaLocation="http://kit.znu.edu.ua/scemes/имя_файла.xsd"<h3">Объявление элемента и атрибута XSD

Процесс создания схемы включает в себя два шага — определение и объявление типов элементов или типов атрибутов. Элементы и атрибуты XML-документа объявляются элементами схемы xsd:element и xsd:attribute. Структура же XML-документа определяется элементами схемы xsd:simpleType и xsd:complexType.

Основное объявление элемента состоит из имени и типа данных

<xsd:element name="имя_элемента" type="xsd:тип_данных"/>

В схемах XSD дескрипторы, используемые в документах XML, разделяются на две категории — сложные типы и простые типы. Элементы сложных типов могут содержать другие элементы, а также обладают определенными атрибутами; элементы простых типов такими возможностями не обладают.

Атрибут - объявление простого типа, которое не может содержать другие элементы. Объявление атрибута похоже на объявление элемента:

<xsd:attribute name="имя_атрибута" type="xsd:тип_данных"/>

Простые типы данных

Есть две главных категории простых типов:

Язык XSD имеет большое количество встроенных простых типов данных. Встроенные типы включают в себя примитивные типы и производные. Примитивные типы данных не получены из других типов данных. Например, числа с плавающей запятой - математическое понятие, которое не получено из других типов данных. Производные типы данных определены в терминах существующих типов данных. Например, целое число - частный случай, полученный из десятичного типа данных.

Следующая таблица представляет список примитивных типов данных XML-схемы, аспекты, которые могут быть применены к типу данных и описания типа данных.

Примитивные типы данных
Тип данных Аспекты Описание
string length, pattern, maxLength, minLength, enumeration, whiteSpace Представляет символьную строку.
Boolean pattern, whiteSpace Представляет логическое значение, которое может быть true или false.
decimal enumeration, pattern, totalDigits, fractionDigits, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет произвольное число.
float pattern, enumeration, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет 32-битовое число с плавающей запятой одиночной точности.
double pattern, enumeration, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет 64-битовое число с плавающей запятой двойной точности.
duration enumeration, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет продолжительность времени. Шаблон для duration следующий - PnYnMnDTnHnMnS, где nY представляет число лет; nM - месяцев; nD - дней; Т - разделитель даты и времени; nH - число часов; nM - минут; nS - секунд.
dateTime enumeration, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет конкретное время. Шаблон для dateTime следующий - CCYY-MM-DDThh:mm:ss, где CC представляет столетие; YY - год; MM - месяц; DD - день; Т - разделитель даты и времени; hh - число часов; mm - минут; ss - секунд. При необходимости можно указывать доли секунды. Например, сотые доли в шаблоне: ss.ss
time enumeration, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет конкретное время дня. Шаблон для time следующий -hh:mm:ss.sss (долевая часть секунд необязательна).
date enumeration, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет календарную дату. Шаблон для date такой - CCYY-MM-DD (здесь необязательна часть, представляющая время).
gYearMonth   enumeration, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет конкретный месяц конкретного года (CCYY-MM ).
gYear enumeration, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет календарный год (CCYY).
gMonthDay enumeration, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет конкретный день конкретного месяца (--MM-DD).
gDay enumeration, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет календарный день (---DD).
gMonth enumeration, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, whiteSpace Представляет календарный месяц (--MM--).
hexBinary length, pattern, maxLength, minLength, enumeration, whiteSpace Представляет произвольную шестнадцатерично-закодированную двоичную информацию. HexBinary - набор двоичных октетов фиксированной длины, состоящий из четырех пар шестнадцатеоисных символов. Например, 0-9a-fA-F.
base64Binary length, pattern, maxLength, minLength, enumeration, whiteSpace Представляет произвольную Base64-закодированную двоичную информацию. Base64Binary - набор двоичных октетов фиксированной длины.
anyURI length, pattern, maxLength, minLength, enumeration, whiteSpace Представляет URI как определено в RFC 2396. Значение anyURI может быть абсолютно или относительно, и может иметь необязательный идентификатор фрагмента.
QName length, enumeration, pattern, maxLength, minLength, whiteSpace Представляет составное имя. Имя составлено из префикса и локального названия, отделенного двоеточием. И префикс и локальные названия должны быть NCNAME. Префикс должен быть связан с namespace URI ссылкой, используя объявление пространства имени.
NOTATION length, enumeration, pattern, maxLength, minLength, whiteSpace Представляет тип атрибута СИСТЕМЫ ОБОЗНАЧЕНИЙ. Набор QNAMES.

Следующая таблица представляет список производных типов данных XML-схемы, аспекты, которые могут быть применены к типу данных и описания типа данных.

Производные типы данных
Тип данных Аспекты Описание
normalizedString length, pattern, maxLength, minLength, enumeration, whiteSpace Представляет нормализованные строки. Этот тип данных получен из string.
token enumeration, pattern, length, minLength, maxLength, whiteSpace Представляет маркированные строки. Этот тип данных получен из normalizedString.
language length, pattern, maxLength, minLength, enumeration, whiteSpace Представляет идентификаторы естественного языка (определенный RFC 1766). Этот тип данных получен из token
IDREFS length, maxLength, minLength, enumeration, whiteSpace Представляет тип атрибута IDREFS. Содержит набор значений типа IDREF.
ENTITIES length, maxLength, minLength, enumeration, whiteSpace Представляет тип атрибута ENTITIES. Содержит набор значений типа ENTITY.
NMTOKEN length, pattern, maxLength, minLength, enumeration, whiteSpace Представляет тип атрибута NMTOKEN. NMTOKEN - набор символов имен (символы, цифры и другие символы) в любой комбинации. В отличие отName и NCNAME, NMTOKEN не имеет никаких ограничений на первый символ. Этот тип данных получен из token.
NMTOKENS length, maxLength, minLength, enumeration, whiteSpace Представляет тип атрибута NMTOKENS. Содержит набор значений типа NMTOKEN.
Name length, pattern, maxLength, minLength, enumeration, whiteSpace Представляет имена в XML. Name - лексема(маркер), которая начинается с символа, символа подчеркивания или двоеточия и продолжается символами имен (символы, цифры, и другие символы). Этот тип данных получен из token.
NCName length, pattern, maxLength, minLength, enumeration, whiteSpace Представляет неколонкированные названия. Этот тип данных - тот же, что и Name, но не может начинаться с двоеточия. Этот тип данных получен из Name.
ID length, enumeration, pattern, maxLength, minLength, whiteSpace Представляет тип атрибута ID, определенный в XML 1.0 Рекомендации. ИДЕНТИФИКАТОР не должен иметь двоеточия (NCName) и должен быть уникален в пределах XML документа. Этот тип данных получен из NCNAME.
IDREF length, enumeration, pattern, maxLength, minLength, whiteSpace Представляет ссылку к элементу, имеющему атрибут ID, который точно соответствует установленному ИДЕНТИФИКАТОРУ. IDREF должен быть NCNAME и должен быть значением элемента или атрибута типа ID в пределах XML документа. Этот тип данных получен из NCNAME.
ENTITY length, enumeration, pattern, maxLength, minLength, whiteSpace Представляет тип атрибута ENTITY. Это - ссылка к неанализируемому объекту с именем, которое точно соответствует установленному имени. ENTITY должен быть NCNAME и должен быть объявлен в схеме как неанализируемое имя объекта. Этот тип данных получен из NCNAME.
integer enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет последовательность десятичных цифр с необязательным знаком (+ или -). Этот тип данных получен из decimal.
nonPositiveInteger    enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число, меньшее или равное нулю. NonPositiveInteger состоит из отрицательного знака (-) и последовательности десятичных цифр. Этот тип данных получен из целого числа.
negativeInteger enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число, меньшее нуля. Этот тип данных получен из nonPositiveInteger.
long enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число с минимальным значением -9223372036854775808 и максимумом 9223372036854775807. Этот тип данных получен из целого числа.
int enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число с минимальным значением -2147483648 и максимумом 2147483647. Этот тип данных получен из long.
short enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число с минимальным значением -32768 и максимумом 32767. Этот тип данных получен из int.
byte enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число с минимальным значением -128 и максимумом 127. Этот тип данных получен из short.
nonNegativeInteger     enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число, большее равное нулю. Этот тип данных получен из целого числа.
unsignedLong enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число с минимумом нуль и максимумом 18446744073709551615. Этот тип данных получен из nonNegativeInteger.
unsignedInt enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число с минимумом нуль и максимумом 4294967295. Этот тип данных получен из unsignedLong.
unsignedShort enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число с минимумом нуль и максимумом 65535. Этот тип данных получен из unsignedInt.
unsignedByte enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число с минимумом нуля и максимума 255. Этот тип данных получен из unsignedShort.
positiveInteger enumeration, fractionDigits, pattern, minInclusive, minExclusive, maxInclusive, maxExclusive, totalDigits, whiteSpace Представляет целое число, которое является большим чем нуль. Этот тип данных получен из nonNegativeInteger.

Определённые пользователем простые типы

Получены из встроенных типов, применением к ним именованых ограничений, называемыми аспектами(Facets). Аспекты ограничивают допустимые значения простых типов. Синтаксис применения аспектов ограничения следующий:

<xsd:restriction base="тип_данных"> <xsd:имя_аспекта value="значение_аспекта"/> </xsd:restriction>

Аспекты ограничения простых типов
Аспект Значение
enumeration Определенный набор значений. Ограничивает тип данных указанными значениями.
fractionDigits    Значение с определенным максимальным числом десятичных цифр в дробной части.
length Целочисленное число единиц длины. Единицы длины зависят от типа данных.
maxExclusive Верхний предел значений (все значения - меньше указанного).
maxInclusive Максимальное значение.
maxLength Целочисленное число единиц максимальной длины.
minExclusive Нижний предел значений (все значения - больше указанного).
minInclusive Минимальное значение.
minLength Целочисленное число единиц минимальной длины.
pattern Литеральный шаблон, которому должны соответствовать значения.
totalDigits Значение с определенным максимальным числом десятичных цифр.
whiteSpace Одно из предопределенных значений: preserve, replace или collapse
Значения аспекта whiteSpace
Значение Описание
preserve Никакая нормализация не выполняется.
replace Все #x9 (tab), #xA (line feed) and #xD (carriage return) заменяются на #x20 (пробел).
collapse После replace-обработки все внутренние цепочки #x20 разрушаются до одного пробела, а окружающие пробелы удаляются.

Аспекты могут быть указаны только однажды в определении типа, кроме enumeration и pattern - они могут иметь многократные вхождения и группируются.

Именованный тип данных

В языке XSD, в отличие от тех двух, с которыми вы познакомились раньше, существует концепция именованных типов. Например, при создании определения, можно присвоить этому определению имя, чтобы повторно использовать его в схеме XSD. Вы можете создать определение простого типа simpleType и назвать его, например, txt15pre. В результате вы получите именованное ограничение. После этого вы сможете применять это ограничение и к другим элементам в схеме. Это особенно полезно, когда в определении применяются аспекты ограничения типа данных, чтобы не повторять их каждый раз в других определениях. Например, элемент simpleType может быть связан с элементом Фамилия и атрибутом Телефон для объявления содержания этих элемента и значения атрибута как строковых данных:

<xsd:simpleType name="txt15pre">
   <xsd:restriction base="xsd:string">
       <xsd:maxLength value="15"/>
       <xsd:whiteSpace value="preserve"/>
   </xsd:restriction>
</xsd:simpleType>
<xsd:element name="Фамилия" type="txt15pre"/>
<xsd:attribute name="Телефон" type="txt15pre" use="required"/>

Обратили внимание на ключевое слово required в объявлении атрибута? Как и в предыдущих схемах, оно все так же означает обязательность использования объявленного атрибута. Другими предопределенными значениями атрибута use элемента схемы xsd:attributeмогут быть ключевые слова optional и prohibited. Если первое из них означает необязательность использования, то второе запрещает использование объявленного атрибута. Такая необходимость возникает в случае локального объявления ранее определенной группы атрибутов элементом схемы xsd:attributeGroup, например:

<xsd:attributeGroup name="Связь">
   <xsd:attribute name="Телефон" type="txt15pre"/>
   <xsd:attribute name="Факс" type="txt15pre"/>
</xsd:attributeGroup>

далее в контексте определения элемента сложного типа мы делаем ограничение на применение атрибутов этой группы:

<xsd:complexType name="Клиент">
   <xsd:complexContent>
       <xsd:restriction base="xsd:Связь">
           <xsd:attribute name="Телефон" use="required"/>
           <xsd:attribute name="Факс" use="prohibited"/>
       </xsd:restriction>
   </xsd:complexContent>
</xsd:complexType>

Сложные типы данных

Модель содержания элемента сложного типа - формальное описание структуры и допустимого содержания элемента, которое используется для проверки правильности XML документа. Модели содержания Схемы предоставляют больший контроль структуры элементов, чем модели содержания DTD. Кроме того, модели содержания схемы позволяют проверять правильность смешанного содержания.

Модель содержания может ограничивать документ до некоторого набора элементных типов и атрибутов, описывать и поддерживать связи между этими различными компонентами и уникально обозначать отдельные элементы. Свободное использование модели содержания позволяет разработчикам изменять структурную информацию.

Перечень объявлений дочерних элементов приводится в структуре группирующих XSD-элементов choicesequence, и all.

Элемент xsd:choice позволяет только одному из элементов, содержащихся в группе присутствовать в составе элемента. Элемент xsd:sequence требует появления элементов группы в точно установленной последовательности в составе элемента. xsd:all элемент позволяет элементам в группе быть (или не быть) в любом порядке в составе элемента.

Элемент xsd:group используется для четкого определения группы и для ссылки к именованной группе. Вы можете использовать модель группы, чтобы определить набор элементов, которые могут быть повторены в документе. Это полезно для формирования определения комплексного типа. Именованную модель группы можно далее определить, используя <xsd:sequence><xsd:choice> или <xsd:all> дочерние элементы. Именованные группы должны определяться в корне схемы. При необходимости многократного использования перечня элементов, определенного в группе, не надо каждый раз писать этот перечень - достаточно дать ссылку на именованную группу <xsd:group ref="имя_группы">

Определение элемента сложного типа

Определения сложных типов создаются с использованием элемента complexType, его атрибутов и любых допустимых аспектов. Обычно, сложные типы будут содержать набор элементных объявлений, объявлений атрибутов и элементных ссылок.

<xsd:element name="имя_элемента" type="xsd:тип_данных">
<xsd:complexType>
   <xsd:sequence>
     <xsd:element name="имя_элемента" type="xsd:тип_данных"/>
   </xsd:sequence>
   <xsd:attribute name="имя_атрибута" type="xsd:тип_данных"/>
</xsd:complexType>
</xsd:element>

Листинг 1. Пример XSD-схемы "Картотека.xsd"

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <xsd:element name="Заказчики">
       <xsd:complexType>
           <xsd:sequence maxOccurs="unbounded">
               <xsd:element name="Заказчик">
                   <xsd:complexType>
                       <xsd:sequence>
                           <xsd:element name="Компания">
                               <xsd:complexType>
                                   <xsd:attribute name="телефон"
                                       type="xsd:string" use="required"/>
                               </xsd:complexType>
                           </xsd:element>
                       </xsd:sequence>
                   </xsd:complexType>
               </xsd:element>
           </xsd:sequence>
       </xsd:complexType>
   </xsd:element>
</xsd:schema>

Задание на лабораторную работу

Необходимо для XML документа, созданого в первой лабораторной работе, определить его струткуру с помощью XSD. Осуществить проверку соответсвия документа описанию его структуры.

W3C парсеры для XML.

Проблемой при валидации (проверка правилоьности XML документа согласно схеме) является тот факт, что соответствие документов их схемам некоторые броузеры не проверяют. В связи с этим возникает необходимость использовать возможности DOM (Document Object Model - см. лаб.раб. №5) для проверки правильности. Функция валидации так или иначе присутствует в любом парсере. Ее необходимо правильно вызвать. Проверить соответствие XDR схеме в ОС Windows несколько легче, поскольку XML парсер от Microsoft является частью операционной системы. Достаточно воспользоваться Java скриптом для проверке (как в прошлой лабораторной работе).

XSD является стандартом, поддерживаемым и развиваемым консорциумом W3C. В рамках этой поддержкиThe Apache Software Foundation создала набор ПО, представляющего собой парсеры и другое обеспечение для работы с XML. Одним из таких известных парсеров является Xerces. Он существует в виде отдельного ПО, реализованного на С++ или Java. Чтобы не ограничивать Вас в выборе инструментальной среды и ОС, будем использовать Java реализацию ввиду ее кроссплатформенности и простоты использования.

Замечание. Для запуска Java приложения необходимо, чтобы на компьютере была установлена Java машина от Sun. Желательно с Java SDK.

Предположим у нас есть XML документ SONNET.XML

<?xml version="1.0"?>
<sonnet
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="sonnet.xsd"
type="Shakespearean">
<author>
   <lastName>Shakespeare</lastName>
   <firstName>William</firstName>
   <nationality>British</nationality>
   <yearOfBirth>1564</yearOfBirth>
   <yearOfDeath>1616</yearOfDeath>
</author>
<title>Sonnet 130</title>
<lines>
   <line>My mistress' eyes are nothing like the sun,</line>
   <line>Coral is far more red than her lips red.</line>
   <line>If snow be white, why then her breasts are dun,</line>
   <line>If hairs be wires, black wires grow on her head.</line>
   <line>I have seen roses damasked, red and white,</line>
   <line>But no such roses see I in her cheeks.</line>
   <line>And in some perfumes is there more delight</line>
   <line>Than in the breath that from my mistress reeks.</line>
   <line>I love to hear her speak, yet well I know</line>
   <line>That music hath a far more pleasing sound.</line>
   <line>I grant I never saw a goddess go,</line>
   <line>My mistress when she walks, treads on the ground.</line>
   <line>And yet, by Heaven, I think my love as rare</line>
   <line>As any she belied with false compare.</line>
</lines>
</sonnet>

И есть соответсвенно схема SONNET.XSD

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="sonnet">
   <xsd:complexType>
     <xsd:sequence>
       <xsd:element ref="author"/>
       <xsd:element ref="title" minOccurs="0"/>
       <xsd:element ref="lines"/>
     </xsd:sequence>
     <xsd:attribute name="type" type="sonnetType"
       default="Shakespearean"/>
   </xsd:complexType>
</xsd:element>
<xsd:simpleType name="sonnetType">
   <xsd:restriction base="xsd:string">
     <xsd:enumeration value="Petrarchan"/>
     <xsd:enumeration value="Shakespearean"/>
   </xsd:restriction>
</xsd:simpleType>
<xsd:element name="author">
   <xsd:complexType>
     <xsd:sequence>
       <xsd:element ref="lastName"/>
       <xsd:element ref="firstName"/>
       <xsd:element ref="nationality"/>
       <xsd:element ref="yearOfBirth" minOccurs="0"/>
       <xsd:element ref="yearOfDeath" minOccurs="0"/>
     </xsd:sequence>
    </xsd:complexType>
</xsd:element>
<xsd:element name="lastName" type="xsd:string"/>
<xsd:element name="firstName" type="xsd:string"/>
<xsd:element name="nationality" type="xsd:string"/>
<xsd:element name="yearOfBirth" type="xsd:string"/>
<xsd:element name="yearOfDeath" type="xsd:string"/>
<xsd:element name="title" type="xsd:string"/>
<xsd:element name="lines">
   <xsd:complexType>
     <xsd:sequence>
       <xsd:element ref="line" minOccurs="14" maxOccurs="14"/>
     </xsd:sequence>
   </xsd:complexType>
</xsd:element>
<xsd:element name="line" type="xsd:string"/>
</xsd:schema>

Готовый DomValidator для проверки правильности XML документа на Java можно скачать здесь.

Скомпилировать DOMValidator можно коммандой:

javac domvalidator.java

Проверить правильность SONNET.XML относительно схемы SONNET.XSD (должна находится в том же каталоге) можно коммандой

java DomValidator sonnet.xml xsd

И при необходимости сам Xerces можно скачать отсюда или с официального сайта.

Размер шрифта:
А
А
А
Цвет сайта:
A
A
A
Изображение:
Вкл.
Выкл.
Обычная версия