Памятка по XSD

Данная статья не является исчерпывающей документацией и написана в первую очередь для себя, чтобы всегда можно было вернуться и вспомнить то, что забыл. Здесь упомянуты все самые важные, по моему мнению, фичи инструмента, а также то, что может быть полезно и актуально в моей работе. Поэтому статья будет полезна начинающим айтишникам и тем, кому нужно освежить свои знания.

Что это?

dc826755497319f5828dc64f4c6c823a.jpeg

Самое главное, что нужно понимать: XSD (XML Schema Definition) — это схема, то есть описание данных взаимодействия. Схемы бывают разные, например, наша XSD, которую обычно используют для описания структур в формате XML, или JSON-schema, — предназначена для описания структур в формате JSON. Использование схем в контрактах API сейчас уже является стандартом де-факто, и вот почему:

  1. Переиспользование. Удобно один раз описать формат и далее везде этим пользоваться, или «переиспользовать» для описания новых форматов на основе существующего.

  2. Валидация, парсинг и рендеринг (десериализация и сериализация). Когда интегрируют две системы (сервиса), формат обычно описывают в одной и передают во вторую в виде схемы. В итоге получается единый формат в обеих системах, и не будет ситуации, когда кто-то отправит сообщение, которое вторая система не сможет провалидировать или распарсить. Важно только своевременно обновлять схему у отправителя и получателя при её изменении, либо внедрить версионирование.

  3. Систематизация и порядок. Когда все контракты описаны в схемах (я считаю, что лучше всего одна схема = один микросервис), возникает порядок, ведь внутри алгоритмов в коде все данные берутся не из воздуха. Благодаря этому также экономится время на разработку, тестирование, и даже иногда поддержку. Тот же аналитик может скачать проект и посмотреть существующие схемы, что даст ему много информации, особенно если схемы тщательно ведутся разработчиками или теми, кто их проектирует.

Одним словом — удобство, вот что даёт использование схемы.

Возвращаясь к XSD, с её помощью можно описать как простейшие типы (string, decimal), так и производные из них (например, string с паттерном регулярки), комплексные типы (объекты/списки), порядок, атрибуты и обязательность полей.

Регулярки, они же регулярные выражения (Regular expression, RegExp) — это

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

Из чего состоит XSD?

Основные объекты, из которых состоит XSD-схема:

Основные объекты

Основные объекты

Обычно структуру строят таким образом, что есть корневой элемент (как на картинке outer) и вложенные элементы (как на картинке inner). Когда элемент сложный, то есть состоит из нескольких других элементов (имеет вложенность), то его считают комплексным (от complexType). Сложный элемент всегда содержит внутри тег complexType, индикатор порядка (как на картинке sequence) и сами вложенные элементы. Подробнее обо всём этом дальше.

Элементы

element — это базовая единица в схеме XSD, которая и представляет собой само поле. Он содержит название (атрибут name) и тип (об этом дальше). Ещё element по умолчанию содержит ограничители частотности minOccurs и maxOccurs, равные единице, даже если их не указывать в виде атрибутов внутри элемента. minOccurs отвечает за минимальное количество повторений элемента, а maxOccurs — за максимальное. Что это означает?

  • Поля без этих атрибутов являются обязательными.

  • Поля с minOccurs=0 являются необязательными.

  • Поля  с maxOccurs="unbounded" являются массивом с неограниченным количеством элементов, но не менее одного. Можно ещё указать вместо unbounded, например, число 5, тогда у поля будет ограничение в виде 1–5 повторений.

  • Поля с заполненными minOccurs=0 и maxOccurs="unbounded" являются необязательным массивом с неограниченным количеством элементов. Здесь также можно указать вместо unbounded число для явного ограничения повторений.

Конечно же, для поля ещё можно задать описание. Делается это с помощью тега annotation и выглядит в схеме так:


  
    Текст с описанием элемента
  

Типы

С ними чуть-чуть сложнее, так как они бывают трёх видов:

  1. Элементарные — используются внутри element с помощью атрибута type и представляют из себя стандартные типы данных вроде string, boolean и т. д.

  2. Кастомные — используются, когда помимо элементарного типа требуется наложение дополнительных ограничений. Чаще всего применяют для создания перечисления возможных значений (enumeration) или наложения на поле (element) какого-нибудь паттерна. Используется с помощью тега simpleType.

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

Enumeration, или Enum, — это

отдельный специальный тип, который довольно часто используют для перечисления возможных значений. Например, можно задать поле с типом клиента (ФЛ, ЮЛ или ИП). Под такое поле можно определить список возможных значений, например: legal, physical и solopreneur. Подробнее можно будет посмотреть дальше в примере.

Типы можно создавать как внутри элемента, так и отдельно извне (причём даже в отдельном файле), чтобы использовать их повторно для разных элементов, а также расширять ими друг друга. Типы, которые объявлены отдельно от элемента, содержат название (атрибут name), с помощью которого этот тип и будет присваиваться элементам или типам для расширения.

Стандартные типы данных, которые поддерживаются в XSD:

  • string;

  • decimal;

  • integer;

  • boolean;

  • date;

  • time.

Поскольку XSD в первую очередь предназначен для описания XML, то с помощью типов можно также задать для элемента атрибуты. Делается это, например, так:


  
    
      
        
        
        
        
      
    
  

А вот так это будет выглядеть в XML-примере:

Монитор

Но я считаю, что использование атрибутов хоть и круто расширяет возможности XML относительно того же JSON’а, зато ухудшает читаемость (не всегда и везде, но ухудшает), а также заведомо запрещает формировать этот JSON на основе схемы.

P.S. Да-да, не смотря на то, что XSD используется в первую очередь для описания структуры сообщения или запроса в формате XML, на самом деле на его основе можно также формировать и JSON. По сути указываешь программе структуру документа — XSD, а далее говоришь, в какой формат эту структуру преобразовать — например, в XML или JSON. То есть возможно ли описать с помощью XSD сообщение в JSON? Да. Нужно ли так делать? Вопрос открытый, так как для проектирования контрактов в формате JSON есть специальные для этого инструменты.

Any

Отдельно хотелось бы рассказать про any. В XSD по умолчанию если не задать какому-то полю тип, то оно будет определено с типом anyType. В anyType можно уложить что угодно. Это полезно для тех случаев, когда не важно, что будет отправляться в поле. Например, можно сделать специальный формат в виде чётко определённого конверта, в котором будут различные сервисные данные, данные отправителя и получателя, а также тело, которое никак не будет проверяться. Такой формат может пригодиться для использования в проекте интеграционной шины с единой точкой входа, своего рода воронки, чтобы быстро обрабатывать сообщения и направлять нужному сервису-получателю. Такой формат может выглядеть так:


  
    
    
    
    
    
  

Вот такое сообщение может быть сформировано на основе этой схемы:


  6e8ae52d-d143-47d3-937b-765005b86b4a
  1970-01-01T00:00:00
  web-service
  library-service
  
    XML Schema
    If you need to create or use formal descriptions of XML vocabularies, the W3C's XML Schema offers a powerful set of tools...
    Eric van der Vlist
  











Помимо типа anyType в XSD существует элемент any. Кроме того, что теперь поле может называться не только body, есть ещё одна особенность: any имеет дополнительную настройку (processContents), которая позволяет уточнить то, как мы хотим его использовать. Возможные значения этой настройки:

  • skip — полностью пропускает валидацию.

  • strict — ожидает, что на месте элемента any будет элемент с одним из описанных по схеме типов. Если такой тип не будет найден, то валидация не будет пройдена.

  • lax — ожидает, что на месте элемента any будет элемент с одним из описанных по схеме типов. Если такой тип не будет найден, то валидация будет пропущена.

Пример выше можно переписать с заменой anyType на any, добавив при этом валидацию по элементу с помощью processContents="strict":






  
    
    
    
  



  
    
    
    
    
    
  

Теперь сообщение будет выглядеть так:


  6e8ae52d-d143-47d3-937b-765005b86b4a
  1970-01-01T00:00:00
  web-service
  library-service
  
    XML Schema
    If you need to create or use formal descriptions of XML vocabularies, the W3C's XML Schema offers a powerful set of tools...
    Eric van der Vlist
  

Вариант с полем notification вместо book также будет обработан корректно. Однако, если положить какое-то другое поле, то валидация не будет пройдена. Для таких случаев подойдёт настройка lax или skip

Типы Any

Типы Any

Индикаторы порядка

Одно из основных понятий в XSD — индикаторы порядка. Чаще всего используются индикаторы sequence и all. sequence необходим в тех случаях, когда требуется чётко определённый порядок полей, то есть последовательность, описанная в схеме, является обязательной. Индикатор all, наоборот, говорит о том, что порядок полей можно не соблюдать. Немного забегая вперёд, можете посмотреть для наглядности в примере XML на элементы внутри user: они как объявлены в XSD, так и передаются. Далее взгляните на массив contactList, который используется с индикатором all: видно, как чередуются поля type и value,   это абсолютно корректно.

Помимо этих двух индикаторов порядка ещё есть choice, который тоже очень удобен и используется как оператор «исключающее ИЛИ», но гораздо реже. То есть, если вместо, например, all использовать choice, то XML будет формироваться с одним из элементов на выбор. Индикатор choice удобнее всего использовать, когда одна XSD используется для описания всех API микросервиса. Например:


  
  
  
  
  
  

Пример

Вот небольшой пример XSD-схемы, в котором я постарался адекватно задействовать почти все описанные выше фичи:

XSD пример


  
    
      
        
          
            
             
              
               
              
             
            
            
          
        
      
    
  

  
    
      
      
      
      
        
          
              
              
          
        
      
      
    
  

  
    
      
        
          
            
              
                
                    
                    
                    
                
              
            
            
          
        
      
    
  

Вот пример XML, который будет сформирован на основе вышеприведённой схемы:


  Иван
  Иванов
  Иванович
  30
  1234567890
  
    
      8(909)999-99-99
      PHONE
    
    
      TELEGRAM
      default_itshnik
    
  

Итак, вышеприведённая схема состоит из трёх основных объектов: элемента user и двух типов personType и contactListType. user здесь корневой и основной элемент XSD, который расширяется типом personType. Сам user содержит в себе только два элемента: inn и contactList, а расширение типом personType добавляет базовые поля личности: ФИО, пол, возраст.

Из интересного в примере:

  1. Поле inn имеет кастомный тип, который «базируется» на типе string, но имеет определённый паттерн, описанный с помощью регулярного выражения. Таким образом, мы получили обязательное поле, которое будет валидно только в том случае, если его заполнить 12-ю или 10-ю цифрами.

  2. В двух местах схемы я использовал Enum'ы. Суть примерно та же, что и у элемента inn, поле также базируется на типе string, однако вместо паттерна используется ограничение в виде возможных вариантов заполнения. Например, поле type элемента contact может быть заполнено исключительно тремя значениями: EMAIL, PHONE или TELEGRAM.

Заключение

Принято считать, что XML медленно, но верно умирает (соответственно, и XSD тоже). И всё же в моём сердце они занимают отдельное место. Для меня XSD вместе с XML — понятная и наглядная структура, которая имеет кучу возможностей. А умирает, потому что на замену SOAP пришёл модный и молодёжный простой и тоже решающий почти все проблемы REST поверх HTTP. С его появлением и почти повсеместным использованием количество XML начало сокращаться в пользу JSON.

Кстати, у меня есть Telegram-канал «Айтишник обыкновенный», где я делюсь опытом и знаниями из IT-индустрии, а также выкладываю мемы. Лучшая поддержка — подписка на мой канал ❤️

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

Всем добра!

© Habrahabr.ru