Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

2003 г

Управление перечислениями в W3C XML-схемах

Автор: Энтони Коутс (Anthony Coates)
Перевод: Intersoft Lab
Авторские права: market@iso.ru

Введение

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

<accountSummary>
  <timestamp>2003-01-01T12:25:00</timestamp>
  <currency>USD</currency>
  <balance>2703.35</balance>
  <interest rounding="down">27.55</interest>
</accountSummary>

В этом документе присутствуют два управляемых словаря. Первый - это словарь валют, трехсимвольный код валюты по ISO-4217 ("USD" - это доллар США). Второй - это правило округления (rounding) процентов: "up" (в сторону увеличения), "down" (в сторону уменьшения) и or "nearest" (ближайший). В нашем примере банк предпочитает округлять проценты в сторону уменьшения.

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

В этой статье рассказывается, как можно управлять управляемыми словарями при использовании W3C XML-схемы (W3C XML Schemas), поскольку именно эта спецификация является основным форматом XML-схем для ориентированного на данные XML. Обратите внимание на то, что под "словарями" мы будем понимать перечисляемые списки значений элементов-атрибутов, что отлично от других контекстов, в которых "словари" - это наборы имен элементов XML.

Шаг №1: монолитная схема

Прежде чем задуматься над тем, какой из управляемых словарей находится вне нашего контроля, первое, что необходимо сделать, это создать схему для обобщённых счётов, используя W3C XML-схему. В рамках этой статьи мы воспользуемся подмножеством трехсимвольных кодов валют ISO. Соответствующая схема будет иметь следующий вид:

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

  <xsd:element name = "accountSummary">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref = "timestamp"/>
        <xsd:element ref = "currency"/>
        <xsd:element ref = "balance"/>
        <xsd:element ref = "interest"/>
      </xsd:sequence>
      <xsd:attribute name = "version" use = "required">
        <xsd:simpleType>
          <xsd:restriction base = "xsd:string">
            <xsd:pattern value = "[1-9]+[0-9]*\.[0-9]+"/>
          </xsd:restriction>
        </xsd:simpleType>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name = "timestamp" type = "xsd:dateTime"/>

  <xsd:element name = "currency" type = "iso3currency"/>

  <xsd:element name = "balance" type = "xsd:decimal"/>

  <xsd:element name = "interest">
    <xsd:complexType>
      <xsd:simpleContent>
        <xsd:extension base = "xsd:decimal">
          <xsd:attribute name = "rounding" use = "required"
                         type = "roundingDirection"/>
        </xsd:extension>
      </xsd:simpleContent>
    </xsd:complexType>
  </xsd:element>

  <xsd:simpleType name = "iso3currency">
    <xsd:annotation>
      <xsd:documentation>ISO-4217 3-letter currency codes,
as defined at (трехсимвольные коды валют ISO-4217, как определено по следующему адресу)
http://www.bsi-global.com/Technical+Information/Publications/_Publications/tig90.xalter
or available from (или доступно по следующему адресу)
http://www.xe.com/iso4217.htm
Only a subset are defined here (Здесь определяются только подмножества).</xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base = "xsd:string">
      <xsd:enumeration value = "AUD"/><!-- Australian Dollar -->
      <xsd:enumeration value = "BRL"/><!-- Brazilian Real -->
      <xsd:enumeration value = "CAD"/><!-- Canadian Dollar -->
      <xsd:enumeration value = "CNY"/><!-- Chinese Yen -->
      <xsd:enumeration value = "EUR"/><!-- Euro -->
      <xsd:enumeration value = "GBP"/><!-- British Pound -->
      <xsd:enumeration value = "INR"/><!-- Indian Rupee -->
      <xsd:enumeration value = "JPY"/><!-- Japanese Yen -->
      <xsd:enumeration value = "RUR"/><!-- Russian Rouble -->
      <xsd:enumeration value = "USD"/><!-- US Dollar -->
      <xsd:length value = "3"/>
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:simpleType name = "roundingDirection">
    <xsd:annotation>
      <xsd:documentation>Whether the interest is
rounded up, down or to the
nearest round value.(Округляется ли процент вверх, вниз 
или до ближайшего округленного числа.)</xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base = "xsd:string">
      <xsd:enumeration value = "up"/>
      <xsd:enumeration value = "down"/>
      <xsd:enumeration value = "nearest"/>
    </xsd:restriction>
  </xsd:simpleType>

</xsd:schema>

Обратите внимание на два управляемых словаря (перечисления): простые типы iso3currency и roundingDirection - длина iso3currency явно установлена равной 3, чтобы избежать в будущем досадных опечаток при редактировании, когда потребуется корректировать список валют.

Также стоит отметить, что значению факультативного атрибута version было задано значение "1.0". Дело в том, что при работе с ориентированными на данные XML-сообщениями, часто необходимо одновременно поддерживать многочисленные версии схемы сообщений, поскольку, по-видимому, невозможно одновременно "поднять" системы, использующие эту схему, до ее последней версии. Таким образом, крайне необходимо указать версию схемы, по которой проверялось на допустимость XML-сообщение. С учетом сказанного, мы обозначим нашу схему accountSummary-1.0.xsd, чтобы будущие версии не перезаписали текущую.

Кроме того, для того, чтобы экземпляры сообщения четко идентифицировали свою версию схемы, к элементу accountSummary был добавлен атрибут version. Предполагается, что эти номера версии записываются как M.N, где M - это основной номер версии, а N - дополнительный. В результате, приведенный выше код для обобщённого счёта можно переписать следующим образом:

<accountSummary
  version = "1.0"
  xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation = "accountSummary-1.0.xsd">
  <timestamp>2003-01-01T12:25:00</timestamp>
  <currency>USD</currency>
  <balance>2703.35</balance>
  <interest rounding = "down">27.55</interest>
</accountSummary>

Шаг №2: изолирование изменчивых управляемых словарей

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

В нашем примере обобщённого счёта коды валют - это изменчивый словарь: они контролируются извне, международной организацией ISO, и ISO может добавлять или удалять валюты в любой момент времени. С другой стороны, набор правил округления {"up", "down", "nearest"}, вероятно, не будет меняться, поэтому он является стабильным словарем. Для человека, который осуществляет сопровождение приложения, оперирующего обобщёнными счётами, добавление нового правила округления означало бы написание, тестирование и внедрение новой версии этого приложения. Поэтому "политическое давление" привело бы к тому, что величины округления изменялись бы только как часть запланированного выхода редакции схемы. Таким образом, разумно оставить простой тип roundingDirection встроенным в эту схему.

Тем не менее, вряд ли было бы допустимо переписывать приложение, чтобы отрабатывать изменение в наборе кодов валют, в противном случае это свидетельствовало бы о негибкости разработки. Поскольку эти коды управляются извне, их необходимо изолировать: создадим для них отдельную схему словаря. Схема словаря - это схема, которая содержит единственное определение простого типа с перечисляемыми величинами и больше ничего. Такая схема, обозначенная как iso3currency-1.0.xsd, будет иметь следующий вид:

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

  <xsd:simpleType name = "iso3currency">
    <xsd:annotation>
      <xsd:documentation>ISO-4217 3-letter currency codes,
as defined at (трехсимвольные коды валют ISO-4217, как определено по следующему адресу)
http://www.bsi-global.com/Technical+Information/Publications/_Publications/tig90.xalter
or available from (или доступно по следующему адресу)
http://www.xe.com/iso4217.htm
Only a subset are defined here (Здесь определяются только подмножества).</xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base = "xsd:string">
      <xsd:enumeration value = "AUD"/><!-- Australian Dollar -->
      <xsd:enumeration value = "BRL"/><!-- Brazilian Real -->
      <xsd:enumeration value = "CAD"/><!-- Canadian Dollar -->
      <xsd:enumeration value = "CNY"/><!-- Chinese Yen -->
      <xsd:enumeration value = "EUR"/><!-- Euro -->
      <xsd:enumeration value = "GBP"/><!-- British Pound -->
      <xsd:enumeration value = "INR"/><!-- Indian Rupee -->
      <xsd:enumeration value = "JPY"/><!-- Japanese Yen -->
      <xsd:enumeration value = "RUR"/><!-- Russian Rouble -->
      <xsd:enumeration value = "USD"/><!-- US Dollar -->
      <xsd:length value = "3"/>
    </xsd:restriction>
  </xsd:simpleType>
</xsd:schema>

Видно, словарь валют имеет свою собственную версию и, таким образом, период выхода очередной редакции. Эта схема словаря может быть включена в новую (1.1) версию основной схемы сообщения:

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

  <xsd:include schemaLocation = "iso3currency-1.0.xsd"/>

  <xsd:element name = "accountSummary">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref = "timestamp"/>
        <xsd:element ref = "currency"/>
        <xsd:element ref = "balance"/>
        <xsd:element ref = "interest"/>
      </xsd:sequence>
      <xsd:attribute name = "version" use = "required">
        <xsd:simpleType>
          <xsd:restriction base = "xsd:string">
            <xsd:pattern value = "[1-9]+[0-9]*\.[0-9]+"/>
          </xsd:restriction>
        </xsd:simpleType>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name = "timestamp" type = "xsd:dateTime"/>
  <xsd:element name = "currency" type = "iso3currency"/>
  <xsd:element name = "balance" type = "xsd:decimal"/>

  <xsd:element name = "interest">
    <xsd:complexType>
      <xsd:simpleContent>
        <xsd:extension base = "xsd:decimal">
          <xsd:attribute name = "rounding" use = "required" type = "roundingDirection"/>
        </xsd:extension>
      </xsd:simpleContent>
    </xsd:complexType>
  </xsd:element>

  <xsd:simpleType name = "roundingDirection">
    <xsd:annotation>
      <xsd:documentation>Whether the interest is
rounded up, down or to the
nearest round value.</xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base = "xsd:string">
      <xsd:enumeration value = "up"/>
      <xsd:enumeration value = "down"/>
      <xsd:enumeration value = "nearest"/>
    </xsd:restriction>
  </xsd:simpleType>

</xsd:schema>

В соответствии с правилом обозначения, эта схема названа accountSummary-1.1.xsd. Обратите внимание на отсутствие кодов валют в основной схеме.

Шаг №3: развязывание управляемых словарей

Сложность с accountSummary-1.1.xsd заключается в том, что она напрямую импортирует iso3currency-1.0.xsd. Так, при появлении новой версии схемы словаря валют ISO, по-прежнему требуется выпускать новую редакцию схемы обобщённого счёта. Необходим механизм развязывания версий схемы словаря от версий основной схемы. Простое решение - воспользоваться "проходной" схемой словаря, не имеющей версии:

<xsd:schema xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
  elementFormDefault = "qualified">
  <xsd:include schemaLocation = "iso3currency-1.0.xsd"/>
</xsd:schema>

У этой схемы, обозначенной как iso3currency.xsd, отсутствует атрибут version. Для завершения развязывания схем выпускается новая версия основной схемы, accountSummary-1.2.xsd, - единственное ее отличие от версии 1.1 состоит в том, что элемент <xsd:include> изменился с

<xsd:include schemaLocation = "iso3currency-1.0.xsd"/>
на
<xsd:include schemaLocation = "iso3currency.xsd"/>

чтобы включить не имеющую версии схему словаря валют. Так выполняется развязывание схем. Если организация ISO изменяет список кодов валют, выходит новая схема валют и корректируется iso3currency.xsd, чтобы она импортировала эту новую схему валют. Основная схема остается без изменений, поскольку она содержит iso3currency.xsd и не зависит от версии схемы словаря валют.

Шаг №4: защита приложений

Подобное развязывание схем словарей не лишено сложностей. Во-первых, по мере того, как будут появляться новые версии схемы словарей валют, существующие файлы экземпляров сделаются недопустимыми, если в них содержатся коды валют, которые были удалены ISO. В некоторых случаях такая ситуация неприемлема, но для нашего примера это возможно. Если файл экземпляра ссылается на код валюты, который более не существует, он станет семантически недопустимым; ему также ничто не мешает оказаться синтаксически недопустимым. Тогда можно воспользоваться синтаксической недопустимостью, чтобы обнаруживать такие экземпляры и направлять их для специальной обработки, чтобы код основного приложения смог заниматься допустимыми кодами валют. Убрав обработку ошибок из основного приложения, можно сократить код основного приложения и упростить его сопровождение.

Во-вторых, с учетом того, что коды валют могут менять в любой момент, необходимо обеспечить синхронизацию между кодами валют в схеме словаря валют и кодами валют, известным приложениям. Эту задачу можно решить двумя способами. В первом случае приложения могут воспользоваться схемой словаря как источником кодов валют. Если рассматривать схему словаря как XML-файл, быстрый SAX-парсер - это все, что требуется, чтобы вытащить элементы <xsd:enumeration>, содержащие допустимые величины. При втором подходе коды валют хранятся в центральной реляционной базе данных. Тогда приложения могут обращаться к ее таблице напрямую, а схема словаря может быть динамически генерироваться из этой же таблицы. Любой из описанных методов обеспечивает синхронность наборов допустимых величин по приложениям.

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

Структура схем словарей не должна изменяться ни при каких условиях. Если в схему словаря было бы добавлено новое определение простого или сложного типа или элемента, это могло изменить результаты проверки допустимости экземпляра по основной схеме и привести к сбою в работе базового приложения. Таким образом, необходимо "проверять на допустимость" схемы словарей, чтобы быть уверенным, что они содержат только одно определение простого типа с перечисляемыми величинами. Именно такую ситуацию описал Уилл Провост (Will Provost) в своей статье "Работа с метасхемой" ("Working with a Metaschema").

Очевидным решением было бы написание в качестве метасхемы схемы для схем словарей. На практике автор статьи не стал бы это делать. Известно, что существующая "Схема для схем" ("Schema for Schemas") не на все 100% верна при описании синтаксиса, и именно по этой причине редакторы схем используют ее в качестве справочного, а не нормативного руководства. По этой же причине, а также из-за того, что формат схемы словаря довольно простой, воспользуемся следующей схемой Schematron (Schematron schema):

<sch:schema
  xmlns = "http://www.w3.org/2001/XMLSchema"
  xmlns:sch = "http://www.ascc.net/xml/schematron"
  xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
  xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation =
    "http://www.ascc.net/xml/schematron schematron-1.5.xsd">

  <sch:title>Controlled vocabulary validation (Проверка допустимости
             управляемого словаря)</sch:title>

  <!-- The input is assumed to be a valid W3C XML Schema. -->
  <!-- (Предполагается, входные данные допустимая W3C XML-схема). -->
  <!-- This just checks that it is also a valid           -->
  <!-- vocabulary Schema.                                 -->
  <!-- (Ниже просто проверяется допустимость Схемы словаря).           -->

  <sch:pattern name = "controlled-vocabulary-schema">
    <sch:rule context = "schema">
      <sch:assert test = "count(*) = count(simpleType[@name])"
      >The schema must contain only a
       single simple type definition
       (Эта схема должна содержать только
	   одно определение простого типа).</sch:assert>
      <sch:assert test = "count(simpleType[@name]) = 1"
      >The schema must contain a single simpleType
       definition or a single include
	   (Эта схема должна содержать одно определение
	   simpleType или один элемент include).</sch:assert>
    </sch:rule>

    <sch:rule context = "simpleType">
      <sch:assert test = "@name"
      >The simpleType must have a name
	  (simpleType должен иметь атрибут name)..</sch:assert>
      <sch:assert test = "count(restriction) = 1"
      >The simpleType must contain a
       single restriction
	   (simpleType должен содержать одно ограничение).</sch:assert>
      <sch:assert test = "count(*) = count(annotation)+count(restriction)"
      >The simpleType may have an annotation as well as its
       restriction, but no other structure
	   (У simpleType может быть аннотация, а также свои
	   ограничения, но никакая другая структура).</sch:assert>
    </sch:rule>

    <sch:rule context = "restriction">
      <sch:assert test = "enumeration"
      >A restriction must contain enumerated values
	  (Ограничение должно содержать перечисляемые величины).</sch:assert>
    </sch:rule>

    <sch:rule context = "enumeration">
      <sch:key name = "enumerationsByValue" path = "@value"/>
      <sch:assert test = "count(key('enumerationsByValue', @value)) = 1"
      >An enumerated value must be unique
	  (Перечисляемая величина должны быть уникальной).</sch:assert>
    </sch:rule>
  </sch:pattern>
</sch:schema>

Чтобы в среде Windows проверить на допустимость схему словаря по этой схеме Schematron, вы можете воспользоваться бесплатным валидатором от Topologi (free validator from Topologi). Касательно других платформ, смотрите список инструментальных средств в Справочнике ресурсов Schematron (Schematron Resource Directory). Более подробную информацию о Schematron можно найти в статье Чимези Огбуджи (Chimezie Ogbuji) "Проверка допустимости с помощью Schematron" ("Validating XML with Schematron").

Утверждения в Schematron выражаются с помощью выражений, значением которых должна быть true. Если их значением оказывается false, генерируется ошибка проверки допустимости по Schematron. При рассмотрении нашей схемы Schematron стоит отметить следующее:

  • Обратите внимание на правило для контекста schema. Оно содержит утверждения, которые применяются к элементу <xsd:schema> в схеме словаря. Первое утверждение контролирует, что единственное, что содержится в схеме, это определения <xsd:simpleType>. Второе утверждение контролирует, что присутствует только одно определение <xsd:simpleType>.
  • Правило для контекста simpleType утверждает, что, во-первых, у <xsd:simpleType> должен быть атрибут name, а, во-вторых, <xsd:simpleType> должен содержать <xsd:restriction> и может включать <xsd:annotation>, но больше никаких других элементов.
  • Правило для контекста restriction утверждает, что <xsd:restriction>> должно содержать одну или более перечисляемых величин.
  • Правило для контекста enumeration утверждает, что перечисляемые величины должны быть уникальны. Чтобы проверить это, используется ключ Schematron (эквивалентный ключу XSLT). Выражение key('enumerationsByValue', @value) возвращает список элементов <xsd:enumeration> с таким же значением, как и проверяемый на допустимость элемент. Если эти величины уникальны, то в этом списке будет присутствовать только один элемент <xsd:enumeration>, тот, который проверяется на допустимость.

Заключение

Поместив изменчивые управляемые словари (перечисления) в свои собственные схемы словарей, можно повысить управляемость W3C XML-схем. В этой статье было рассмотрено, как идентифицировать изменчивые управляемые словари, как отделять их от основной схемы, как развязывать версии и как проверять на допустимость схемы словарей. Разумеется, абсолютного рецепта - когда у управляемого словаря должна быть своя схема - нет. Поэтому применяя приведенные в этой статье рекомендации, всегда полагайтесь на здравый смысл и знание проблемной области.

Ресурсы

Файл с примерами, приведенными в этой статье можно скачать в виде ZIP-архива (9 кБ).

Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

VPS в России, Европе и США

Бесплатная поддержка и администрирование

Оплата российскими и международными картами

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...