В жизни каждого аналитика и программиста наступает такой день, когда он узнает о существовании шаблонов (паттернов) проектирования 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="City" 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="City" 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:City" />
                            <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="City" 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="City" 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:City"/>
            <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

Комментарии (3)


  1. QtRoS
    20.06.2015 21:14
    +1

    Очень интересный материал на самом деле, удивлен, что в статье нет никакой активности.
    Мы под свои нужды используем «матрешку».