Шаблони проектування XSD

У житті кожного аналітика і програміста настає такий день, коли він дізнається про існування шаблонів (патернів) проектування XML-схем і його життя змінюється. Для мене, наприклад, з цього знання почалося осягнення краси проектування.

Сьогодні хочу поговорити про те, які є шаблони проектування XSD, про переваги та недоліки кожного, і чому ми для своїх завдань вибрали «Райський сад».



Для прикладу візьмемо наступний документ XML в якості джерела даних.

<?xml version="1.0" encoding="UTF-8"?>
<Customer>
<CustomerId>100</CustomerId>
<FirstName>Павло</FirstName>
<LastName>Орлов</LastName>
<Address>
<StreetAddress>Угрешская 2</StreetAddress>
<City>Москва</City>
<Zip>115088</Zip>
</Address>
</Customer>

І подивимося, як можна описати одну і ту ж структуру XML-документа різними способами.
В основі поділу на шаблони лежить принцип визначення глобальних елементів і/або типів даних всередині XSD.

Матрьошка (Russian Doll)

Суть шаблону в тому, що схема є дзеркалом описуваного нею XML-документа: якщо складні елементи містять всередині себе інші складні елементи, а ті в свою чергу містять прості, то і в XSD опису таких елементів будуть вкладені один в одного. Назва шаблон отримав на честь відомої у всьому світі нашої ляльки-матрьошки, за аналогією з тим, як дочірні елементи шаблону інкапсулюються в батьківські.

Схема, що описує структуру нашого файлу-джерела з використанням шаблону «Матрьошка», виглядає так:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/Customer" xmlns:tns="http://www.example.org/Customer" elementFormDefault="qualified">

<xsd:element name="Customer">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="CustomerId" type="xsd:int" />
<xsd:element name="FirstName" type="xsd:string" />
<xsd:element name="LastName" type="xsd:string" />
<xsd:element name="Address">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="StreetAddress" type="xsd:string"/>
<xsd:element name="Центр" type="xsd:string"/>
<xsd:element name="Zip" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

</xsd:schema>

Характеристики шаблону:
  • Непрозорість змісту. Зміст XSD непрозоро для інших схем, і навіть для інших частин тієї ж схеми. Внаслідок чого жоден з типів або елементів всередині XSD не може бути повторно використаний.
  • Приховані області. Області схеми, в якій визначаються локальні елементи («City» і «Zip» в прикладі), локалізовані всередині кореневого елемента («Address»). В результаті якщо задати в схемі elementFormDefault = «unqualified», то простору імен локальних елементів («City» і «Zip») приховані в межах схеми.
  • Незалежність. При такій конструкції кожен компонент схеми є автономним (тобто не взаємопов'язаний з іншими компонентами). Отже, зміни окремих компонентів буде мати обмежений вплив. Наприклад, якщо додати до складу адреси елемент «FlatNumber», це ніяк не вплине на інші елементи схеми.
  • Компактність. Завдяки такій конструкції всі пов'язані за змістом дані об'єднуються в схемі в автономні компоненти, тобто компоненти є компактними.


Салямі (Salami Slice)

Суть шаблону в тому, що описуваний XML-документ поділяється на складові елементи, кожен з яких описується в XSD як глобальний. Потім описані елементи з'єднуються воєдино.

Схема, що описує структуру файлу-джерела з використанням шаблону «Салямі», виглядає так:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/Customer"
xmlns:tns="http://www.example.org/Customer"
elementFormDefault="qualified">

<xsd:element name="CustomerId" type="xsd:int" />
<xsd:element name="FirstName" type="xsd:string" />
<xsd:element name="LastName" type="xsd:string" />
<xsd:element name="StreetAddress" type="xsd:string"/>
<xsd:element name="Центр" type="xsd:string"/>
<xsd:element name="Zip" type="xsd:string"/>

<xsd:element name="Customer">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="tns:CustomerId" />
<xsd:element ref="tns:FirstName" />
<xsd:element ref="tns:LastName" />
<xsd:element name="Address">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="tns:StreetAddress" />
<xsd:element ref="tns:Центр" />
<xsd:element ref="tns:Zip" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

</xsd:schema>

Характеристики шаблону:
  • Прозорість змісту. Всі елементи можуть бачити інші схеми, а також інші компоненти цієї XSD.
  • Глобальність. Так як всі елементи схеми оголошені глобально, то незалежно від значення elementFormDefault простору імен схеми в XML-документі буде показаний весь набір атрибутів (що може бути порожнім).
  • Взаємозалежність. При такій конструкції складні елементи посилаються на інші частини схеми, тобто залежать від них. Отже, зміна окремих компонентів можуть спричинити великі зміни всієї схеми.
  • Компактність. Завдяки такій конструкції всі пов'язані за змістом дані об'єднуються в схемі в автономні компоненти, тобто компоненти є компактними.


Венеціанські жалюзі (Venetian Blind)

Суть шаблону в тому, що описуваний XML-документ поділяється на складові типи, кожен з яких описується в XSD як глобальний. Потім оголошується кореневий елемент, відповідний глобального типу, що з'єднує схему воєдино.

Схема, що описує структуру файлу-джерела з використанням шаблону «Венеціанські жалюзі», виглядає так:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/Customer"
xmlns:tns="http://www.example.org/Customer"
elementFormDefault="qualified">

<xsd:complexType name="AddressType">
<xsd:sequence>
<xsd:element name="StreetAddress" type="xsd:string"/>
<xsd:element name="Центр" type="xsd:string"/>
<xsd:element name="Zip" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="CustomerType">
<xsd:sequence>
<xsd:element name="CustomerId" type="xsd:int" />
<xsd:element name="FirstName" type="xsd:string" />
<xsd:element name="LastName" type="xsd:string" />
<xsd:element name="Address" type="tns:AddressType" />
</xsd:sequence>
</xsd:complexType>

<xsd:element name="Customer" type="tns:CustomerType" />

</xsd:schema>

Характеристики шаблону:
  • Прозорість змісту. Типи даних видно з інших схем, а також видно компонентів XSD.
  • Максимальне приховування імен. Оголошення елементів локальні, тому шаблон має максимальний потенціал для приховування імен.
  • Просте управління відображенням пустих атрибутів. Якщо простору імен приховані, то показувати чи ні порожні атрибути в документах управляється одним перемикачем elementFormDefault.
  • Взаємозалежність. При такій конструкції складні типи даних посилаються на інші частини схеми, тобто залежать від них. Отже, зміна окремих компонентів можуть спричинити великі зміни всієї схеми.
  • Компактність. Завдяки такій конструкції всі пов'язані за змістом дані об'єднуються в схемі в автономні компоненти, тобто компоненти є компактними.


Райський сад (Garden of Eden)

«Райський сад» хороший тим, що визначає кожен елемент і складовою тип даних як глобальний. Це дозволяє посилатися на будь-який тип або елемент в межах одного XSD або іншого XSD і навіть з WSDL. Тільки так можна повністю контролювати семантику та типів та елементів.

Схема, що описує структуру файлу-джерела з використанням шаблону «Райський сад», виглядає так:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/Customer"
xmlns:tns="http://www.example.org/Customer"
elementFormDefault="qualified">

<xsd:element name="CustomerId" type="xsd:int"/>
<xsd:element name="FirstName" type="xsd:string"/>
<xsd:element name="LastName" type="xsd:string"/>
<xsd:element name="StreetAddress" type="xsd:string"/>
<xsd:element name="Центр" type="xsd:string"/>
<xsd:element name="Zip" type="xsd:string"/>

<xsd:element name="Address" type="tns:AddressType"/>
<xsd:element name="Customer" type="tns:CustomerType"/>

<xsd:complexType name="AddressType">
<xsd:sequence>
<xsd:element ref="tns:StreetAddress"/>
<xsd:element ref="tns:Центр"/>
<xsd:element ref="tns:Zip"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="CustomerType">
<xsd:sequence>
<xsd:element ref="tns:CustomerId"/>
<xsd:element ref="tns:FirstName"/>
<xsd:element ref="tns:LastName"/>
<xsd:element ref="tns:Address"/>
</xsd:sequence>
</xsd:complexType>

</xsd:schema>

Характеристики шаблону:
  • Максимальна прозорість змісту. І типів, і елементи даних видно з інших схем, а також видно компонентів XSD.
  • Максимальне розкриття імен. Нічого локально не визначається, тому видимість імен максимальна.
  • Взаємозалежність. При такій конструкції складні типи даних та елементи посилаються на інші частини схеми, тобто залежать від них. Отже, зміна окремих компонентів можуть спричинити великі зміни всієї схеми.
  • Громіздкість. Пов'язані за змістом дані «розмазані» по визначенню типу і елемента. «Читати» таку схему складніше.


Вибір шаблону

При виборі шаблону важливо враховувати кілька критеріїв:
  1. Наскільки можливо повторне використання компонентів схеми;
  2. Наскільки легко зі схемою працювати;
  3. Наскільки компоненти схеми повинні бути взаємозалежні або незалежні.


Часто при виборі шаблону проектування доводиться шукати баланс між можливістю повторно використовувати компоненти схеми і глибиною взаємозв'язки між компонентами. На малюнку показаний потенціал кожного з шаблонів в розрізі цих двох аспектів.



Ті схеми, в яких добре підтримується повторне використання компонентів, з іншого боку мають сильні взаємозв'язки між компонентами. При необхідності щось змінити в такій схемі розробник схеми може зіткнутися з тим, що змінювати доведеться багато пов'язаних елементів і/або типів. Такими схемами згодом важко керувати.

В цілому можна вивести наступні правила вибору шаблону:
  • якщо повторне використання компонентів схеми не є необхідним, якщо важливіше зручність використання XSD розробниками, і суворої необхідності контролювати імена компонентів немає, то слід вибирати «Матрьошку»;
  • якщо повторне використання компонентів важливіше зручності для розробників, а імена елементів даних потрібно контролювати в межах всієї системи, то слід вибирати «Салямі»;
  • якщо додатково до попереднього пункту важливо контролювати найменування типів даних і мати можливість повторно використовувати типи даних, слід вибирати «Райський сад»;
  • «Венеціанські жалюзі» підійдуть у тому випадку, якщо важливо і повторне використання компонентів, і свобода у визначенні їх локальних імен (або можливість приховати їх усередині схеми).


Нам у проекті важливіше всього було повторне використання типів та елементів схеми і в другу чергу тотальний семантичний контроль імен. Вибір шаблону був очевидний – Райський сад.

Невеликий ліричний відступ. Самим цікавим застосуванням шаблонів проектування XML-схем на моїй пам'яті був і залишається гіпноз аудиторії. Один наш титулований аналітик любить брати ініціативу в свої руки через розповідь на цю тему. Засекала час, через 5 хвилин погляд слухачів тьмяніє, і вони йдуть кудись далеко в себе. На «Райський сад» свідомість більшості відключається.

І у висновку хочу додати, що мікси шаблонів теж можливі, ми з ними зустрічалися.

Джерела і ресурси:
XML-Schema специфікація
Schema scope: Primer and best practices
Introducing Design Patterns in XML Schemas

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.