Практика використання просторів імен XML в проектах

Автор: Bладімір Енгельс, Oracle СНД

Введення

При реалізації типових SOA-проектів, як правило, створюється кілька XML-схем. У цих випадках проектувальник XML-схем повинен вирішити наступне питання:


Який підхід буде більш оптимальний? Яким посібникам потрібно слідувати, починаючи роботу над SOA-проектами, у яких створюється кілька XML-схем?

Точності заради, треба відзначити, що є три проектних підходу при роботі з декількома XML-схемами:


  1. гетерогенне простір імен – Кожній XML-схемі присвоюється свій targetNamespace;
  2. гомогенне простір імен – Всім XML-схемами присвоюється єдиний targetNamespace;
  3. простір імен типу "хамелеон" – Головної XML-схемі присвоюється targetNamespace, а допоміжним XML-схемами не присвоюється ніякого targetNamespace (XML-схеми без targetNamespace використовують targetNamespace головною XML-схеми при об'єднанні як хамелеон).

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

Приклад: XML-модель даних компанії

Уявімо собі проект, який вимагає створення моделі даних компанії, використовуючи XML-схеми. Дана модель створюється у вигляді наступних трьох XML-схем:


Це можна охарактеризувати як "інформація про компанії включає в себе дані по персоні і по продукту". Наведемо три схеми для кожного проектного підходу.

Гетерогенне простір імен

Даний проектний підхід передбачає використання для кожної XML-схеми свого targetNamespace. Нижче наводиться три схеми, спроектовані із застосуванням даного проектного підходу.

Product.xsd

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
targetNamespace=”http://www.product.org”
xmlns=”http://www.product.org”
elementFormDefault=”unqualified”>
xmlns:per=”http://www.person.org”
xmlns:pro=”http://www.product.org”>
<xsd:complexType name=”ProductType”>
<xsd:sequence>
<xsd:element name=”Type” type=”xsd:string”/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Person.xsd

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
targetNamespace=”http://www.person.org”
xmlns=”http://www.person.org”
elementFormDefault=”unqualified”>
<xsd:complexType name=”PersonType”>
<xsd:sequence>
<xsd:element name=”Name” type=”xsd:string”/>
<xsd:element name=”SSN” type=”xsd:string”/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Company.xsd

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
targetNamespace=”http://www.company.org”
xmlns=”http://www.company.org”
elementFormDefault=”unqualified”
xmlns:per=”http://www.person.org”
xmlns:pro=”http://www.product.org”>
<xsd:import namespace=”http://www.person.org”
schemaLocation=”Person.xsd”/>
<xsd:import namespace=”http://www.product.org”
schemaLocation=”Product.xsd”/>
<xsd:element name=”Company”>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=”Person” type=”per:PersonType”
maxOccurs=”unbounded”/>
<xsd:element name=”Product” type=”pro:ProductType”
maxOccurs=”unbounded”/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

Зверніть увагу, що в схемах використовується три різних простору імен:

http://www.product.org
http://www.person.org
http://www.company.org

Гомогенне простір імен

Даний проектний підхід передбачає використання єдиного targetNamespace для всіх XML-схем. Нижче наводиться три схеми, спроектовані із застосуванням даного проектного підходу.

Product.xsd

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
targetNamespace=”http://www.company.org”
xmlns=”http://www.product.org”
elementFormDefault=”qualified”>
<xsd:complexType name=”ProductType”>
<xsd:sequence>
<xsd:element name=”Type” type=”xsd:string”/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Person.xsd

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
targetNamespace=”http://www.company.org”
xmlns=”http://www.person.org”
elementFormDefault=”qualified”>
<xsd:complexType name=”PersonType”>
<xsd:sequence>
<xsd:element name=”Name” type=”xsd:string”/>
<xsd:element name=”SSN” type=”xsd:string”/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Company.xsd

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
targetNamespace=”http://www.company.org”
xmlns=”http://www.company.org”
elementFormDefault=”qualified”>
<xsd:include schemaLocation=”Person.xsd”/>
<xsd:include schemaLocation=”Product.xsd”/>
<xsd:element name=”Company”>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=”Person” type=”PersonType”
maxOccurs=”unbounded”/>
<xsd:element name=”Product” type=”ProductType”
maxOccurs=”unbounded”/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

Зверніть увагу, що у всіх трьох схемах використовується єдине просторів імен:

http://www.company.org

Також зверніть увагу, що для об'єднання XML-схем, що використовують єдиний простір імен, застосовується механізм <include>.

Простір імен типу "хамелеон"

Даний проектний підхід передбачає використання targetNamespace тільки для головної XML-схеми, а допоміжним XML-схемами не присвоюється ніякого targetNamespace. Нижче наводиться три схеми, спроектовані із застосуванням даного проектного підходу. У даному прикладі XML-схема Company.xsd є головною, XML-схеми Product.xsd і Person.xsd – допоміжні.

Product.xsd (немає targetNamespace)

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
elementFormDefault=”qualified”>
<xsd:complexType name=”ProductType”>
<xsd:sequence>
<xsd:element name=”Type” type=”xsd:string”/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Person.xsd (немає targetNamespace)

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
elementFormDefault=”qualified”>
<xsd:complexType name=”PersonType”>
<xsd:sequence>
<xsd:element name=”Name” type=”xsd:string”/>
<xsd:element name=”SSN” type=”xsd:string”/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Company.xsd

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
targetNamespace=”http://www.company.org”
xmlns=”http://www.company.org”
elementFormDefault=”qualified”>
<xsd:include schemaLocation=”Person.xsd”/>
<xsd:include schemaLocation=”Product.xsd”/>
<xsd:element name=”Company”>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=”Person” type=”PersonType”
maxOccurs=”unbounded”/>
<xsd:element name=”Product” type=”ProductType”
maxOccurs=”unbounded”/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>>

Зверніть увагу на два аспекти при використанні даного проектного підходу:


"Ефект хамелеона …" – Цей термін ввів Генрі Томпсон (Henry Thompson).

Вплив проектних підходів на XML-документи

Вище було продемонстровано, як могли б бути спроектовані XML-схеми з застосуванням трьох проектних підходів. Тепер звернемося до XML-документами. Чи відрізняється створення XML-документів, в залежності від застосування того чи іншого проектного підходу? Всі вищенаведені XML-схеми були спроектовані з вимогою явної вказівки просторів імен в XML-документах (на що вказує: elementFormDefault = "qualified"). Якби вони використовували замість цього elementFormDefault = "unqualified", то XML-документ для всіх трьох випадків мав би таку форму:

<?xml version=”1.0″?>
<c:Company xmlns:c=”http://www.company.org”
xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation = "http://www.company.org/Company.xsd">
<Person>
<Name>John Doe</Name>
<SSN>123-45-6789</SSN>
</Person>
<Product>
<Type>Widget</Type>
</Product>
</c:Company>

Як же будуть виглядати XML-документи для наших трьох підходів проектування?

Company.xml (для версії з гетерогенним простором імен в targetNamespace)

<?xml version=”1.0″?>
<Company xmlns=”http://www.company.org”
xmlns:pro=”http://www.product.org”
xmlns:per=”http://www.person.org”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi: schemaLocation = "http://www.company.org/Company.xsd">
<Person>
<per:Name>John Doe</per:Name>
<per:SSN>123-45-6789</per:SSN>
</Person>
<Product>
<pro:Type>Widget</pro:Type>
</Product>
</Company>

Зверніть увагу на наступне:


Company.xml (для версії з гомогенним простором імен в targetNamespace)

<?xml version=”1.0″?>
<Company xmlns=”http://www.company.org”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi: schemaLocation = "http://www.company.org/Company.xsd">
<Person>
<Name>John Doe</Name>
<SSN>123-45-6789</SSN>
</Person>
<Product>
<Type>Widget</Type>
</Product>
</Company>

Оскільки всі схеми належать одному простору імен, то в XML-документах для даної ситуації можна скористатися перевагою використання простору імен "по-замовчуванню".

Company.xml (для версії з простором імен типу "хамелеон" в targetNamespace)

<?xml version=”1.0″?>
<Company xmlns=”http://www.company.org”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi: schemaLocation = "http://www.company.org/Company.xsd">
<Person>
<Name>John Doe</Name>
<SSN>123-45-6789</SSN>
</Person>
<Product>
<Type>Widget</Type>
</Product>
</Company>

Обидві схеми XML без визначення targetNamespace взяли targetNamespace XML-схеми Company.xsd (подібно хамелеон-ефекту). Таким чином, всі компоненти належать одному targetNamespace, і в XML-документах для даної ситуації також можна скористатися перевагою використання простору імен "по-замовчуванню".

<redefine> – застосовуваний лише в гомогенному просторі імен і в просторі імен типу "хамелеон"

Елемент <redefine> використовується в XML-схемах для отримання доступу до компонентів в інших XML-схемах і одночасно дає можливість внести якесь число (нуль або більше) змін до визначення імпортованих компонентів. Таким чином, елемент <redefine> виконує подвійну функцію:


Приклад. Розглянемо знову вищенаведену XML-схему Company.xsd. Припустимо, що вона використовує елемент ProductType з Product.xsd. Додатково, під час використання необхідно розширити елемент ProductType і включити в нього елемент ID (ідентифікатор продукту). Наведемо приклад, як це можна зробити, використовуючи елемент <redefine>:

<?xml version=”1.0″?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
targetNamespace=”http://www.company.org”
xmlns=”http://www.company.org”
elementFormDefault=”qualified”>
<xsd:include schemaLocation=”Person.xsd”/>
<xsd:redefine schemaLocation=”Product.xsd”>
<xsd:complexType name=”ProductType”>
<xsd:complexContent>
<xsd:extension base=”ProductType>
<xsd:sequence>
<xsd:element name="ID" type="xsd:ID"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:redefine>

<xsd:element name=”Company”>
<xsd:complexType>
<xsd:sequence>
<Xsd: element name = "Person" type = "PersonType"
maxOccurs=”unbounded”/>
<Xsd: element name = "Product" type = "ProductType"
maxOccurs=”unbounded”/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

Тепер елемент <Product> в XML-документі повинен містити обидва елементи <Type> і <ID>, тобто:

<?xml version=”1.0″?>
<Company xmlns=”http://www.company.org”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi: schemaLocation = "http://www.company.org/Company.xsd">
<Person>
<Name>John Doe</Name>
<SSN>123-45-6789</SSN>
</Person>
<Product>
<Type>Widget</Type>
<ID>1001-01-00</ID>
</Product>
</Company>

Елемент <redefine> має дуже великий проектної міццю. Правда, використовуватися він може тільки в XML-схемах з єдиним простором імен або в XML-схемах без вказівки простору імен. Таким чином, елемент <redefine> може бути застосовний тільки проектних підходах з гомогенним простором імен і з простором імен типу "хамелеон".

Простір імен "по-замовчуванню" і проектний підхід типу "хамелеон"

Якщо XML-схема припускає використання елемнта <include> в рамках проетного підходу типу "хамелеон" (використовуючи схеми без визначення targetNamespace), то головна схема повинна оголошувати простір імен з targetNamespace також як простір імен "по-замовчуванню".

Як уникнути колізії імен при використанні підходу типу "хамелеон"

Колізія імен

Коли головна XML-схема використовує хамелеон-комоненти, то ці компоненти стають частиною простору імен (зазначеного в targetNamespace) головною XML-схеми, так як ніби проектувальник XML-схеми використовував in-line декларацію елементів і типів. Якщо головна схема включає (<include>) кілька XML-схем без вказівки простору імен, то існує шанс, що виникне колізія імен. Таким чином, головна XML-схема не зможе використовувати деякі компоненти допоміжних XML-схем (в яких не вказано простір імен), оскільки для них має місце колізія імен з елементами з інших допоміжних XML-схем. Для демонстрації проблеми колізії імен, розглянемо наступний приклад.

Припустимо, існує дві схеми XML без вказівки targetNamespace:

1.xsd
A
B

2.xsd
A
C


XML-схема 1.xsd визначає елементи A і B без вказівки простору імен.
XML-схема 2.xsd визначає елементи A і C без вказівки простору імен.
Тепер, якщо XML-схема 3.xsd включає в себе (<include>) дві зазначені XML-схеми без вказівки простору імен, виникає колізія імен для елемента A, оскільки його оголошено два рази:

3.xsd
targetNamespace=”http://www.example.org”
<include schemaLocation=”1.xsd”/>
<include schemaLocation=”2.xsd”/>

Зверніть увагу, що помилкою не є існування визначення двох елементів з однаковим ім'ям, якщо вони належать до одного типу. Якщо ж вони належать різним типам, то це помилка, і має місце колізія імен.

Стандартним механізмом виключення колізій імен як раз і є застосування просторів імен. Якщо б у наведеному вище прикладі компоненти XML-схем 1.xsd і 2.xsd перебували б у різних просторах імен і вони були б імпортовані в XML-схему 3.xsd, то колізії імен не виникло. [Зауважте, що два компоненти можуть мати однакове ім'я, якщо компоненти належать різним просторів імен.]

А як же вирішити проблему колізії імен при використанні просторів імен типу "хамелеон"?

Вирішення проблеми колізії імен із застосуванням проксірующіх XML-схем

Існує дуже просте рішення даної проблеми колізії імен: для кожної включається XML-схеми без вказівки простору імен створюється допоміжна проксірующая XML-схема, в якій задекларовано простір імен і яка сама вже включає (<include>) допоміжні XML-схеми без вказівки просторів імен. Потім головна схема просто імпортує (<import>) всі проксірующіе XML-схеми.

Наведемо приклад демонструє даний проектний підхід:

<!– Поместим “хамелеон”-компоненты XML-схемы 1.xsd
в простір імен, вказане в targetNamespace, даної проксірующей XML-схеми ->
1-proxy.xsd
targetNamespace=”http://www.1-proxy.org”
<xsd:include schemaLocation=”1.xsd”/>

<! – Помістимо "хамелеон"-компоненти XML-схеми 2.xsd
в простір імен, вказане в targetNamespace, даної проксірующей XML-схеми ->
2-proxy.xsd
targetNamespace=”http://www.2-proxy.org”
<xsd:include schemaLocation=”2.xsd”/>

<! – Тепер імпортуємо проксірующіе XML-схеми в головну схему ->
main.xsd
targetNamespace=”http://www.main.org”
<xsd:import namespace=”http://www.1-proxy.org”
schemaLocation=”1-proxy.xsd”/>
<xsd:import namespace=”http://www.2-proxy.org”
schemaLocation=”2-proxy.xsd”/>


Застосовуючи даний проектний підхід, нам вдалося уникнути колізії імен. Більше того, у цього проектного підходу є ще одне додаткове перевагу: у рамках проксірующіх XML-схем також можна використовувати елемент <redefine> для внесення зміни до хамелеон-компоненти.

Таким чином, даний проектний підхід регламентує триступеневий процес:


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

Порівняємо даний триступеневий процес з раніше описаним двоступінчастим процесом, в якому компонентів призначаються простору імен з самого початку існування компоненти:

1-fixed.xsd
targetNamespace=”http://www.1-fixed.org”
A
B

2-fixed.xsd
targetNamespace=”http://www.2-fixed.org”
A
C

main.xsd
targetNamespace=”http://www.main.org”
<xsd:import namespace=”http://www.1-fixed.org”
schemaLocation=”1-fixed.xsd”/>
<xsd:import namespace=”http://www.2-fixed.org”
schemaLocation=”2-fixed.xsd”/>


Двоступінчастий процес дає той же результат, що і триступеневий. У даному прикладі компоненти вже не є "хамелеонами", і елементи A, B і C жорстко прихильності до відповідних просторів імен з початку життєвого циклу компонентів. Зворотний бік даного підходу – якщо в main.xsd знадобиться внести зміни до визначення компонентів з використанням <redefine>, то це буде неможливо. Крім того, проектувальник головною XML-схеми змушений використовувати простору імен, визначені кимось іншим. Ці компоненти є статичними, незмінними і з фіксованим простором імен.

Засоби, що полегшують використання хамелеон-компонентів

Опис проблеми ідентифікації хамелеон-компонентів

Ми вже кілька разів спостерігали, що хамелеон-компоненти можуть змішуватися в схемах, які їх використовують. Це відбувається, коли вони приймають простір імен включають (<include>) їх XML-схем. Якими ж засобами можна ідентифікувати компоненти, які мають багато уявлень, що відносяться до різних просторів імен?

Припустимо, існують такі схеми XML без визначення просторів імен:

1.xsd
A
B

Далі ми визначаємо головну XML-схему main.xsd, яка включає (<include>) допоміжну XML-схему "хамелеон" 1.xsd, а також сама містить визначення елементу з ім'ям A (оскільки він знаходиться в іншому символьному оточенні – всередині елемента <stuff>, це не призведе до колізії імен).

main.xsd
targetNamespace=”http://www.example.org”
<include schemaLocation=”1.xsd”/>
<element name=”stuff”>
<complexType>
<sequence>
<element name=”A” type=”xxx”/>

</sequence>
</complexType>
</element>

Припустимо, в процесі трансформації нам необхідно чітко ідентифікувати хамелеон-компонент A, незалежно від того, до якого простору імен вони, можливо, будуть належати в майбутньому. Як нам відрізнити хамелеон-компонент A від локально визначеного в XML-схемі компонента A?


Ідентифікація хамелеон-компонентів

Існує одна проста засіб – при створенні хамелеон-компонента призначити йому глобально унікальний ідентифікатор (GUID). Специфікація XML Schema дозволяє додавати атрибут id для елемента, атрибута, а також для компонентів простого та комплексного типів. Зверніть увагу, що атрибут id виключно локальний для XML-схеми, і він ніколи не потрапляє в XML-документ. Саме цей атрибут можна використовувати для точної ідентифікації хамелеон-компонента, незалежно від його поточного простору імен.

Питання: що відбудеться, якщо через проблеми мережі, XML-процесор не зможе отримати доступ до XML-схемі, яка містить необхідні визначення?

Як і у випадку з DTD-визначеннями відбудеться виняткова ситуація в XML-процесорі. Рішення даної проблеми – завжди зберігати копії використовуваних XML-схем локально.



Вище були описані проектні підходи стосовно до використання просторів імен XML в проектах. Були розглянуті як XML-схеми, так і XML-документи для кожного з трьох проектних підходів.

Тепер залишилося відповісти на головне питання: який підхід кращий, і в якому випадку?

Якщо в проекті використовується XML-схема, створена і контрольована кимось іншим, то необхідно використовувати імпортування (<import>) даної XML-схеми, тобто використовувати проектний підхід з гетерогенним простором імен. Копіювати такі компоненти в простір імен проекту – не дуже вдала ідея з двох причин:


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

Використовуйте простір імен типу "хамелеон":


  • з XML-схемами, які містять компоненти, які не мають спадкової семантикою самі по собі;
  • з XML-схемами, які містять компоненти, які мають семантикою тільки в контест головною XML-схеми;
  • коли немає бажання жорстко призначати простір імен для XML-схеми, щоб мати можливість призначати проектованим компонентів спецефічні простір імен того додатка, в якому вони будуть використані.

      Приклад. Репозиторій таких компонентів як, наприклад, XML-схема, що визначає типи масиву, вектора, пов'язаного списку і т. п., повинні визначатися без вказівки targetNamespace (тобто як хамелеон-XML-схема).

      Якщо XML-схема містить тільки визначення типів (відсутні декларації елементів), то вона також хороший кандидат на використання хамелеон-простору імен.


      Використовуйте гомогенне простір імен:



      • якщо все XML-схеми концептуально співвідносяться один з одним;
      • якщо немає необхідності візуально ідентифікувати в XML-документі приналежність елементів і атрибутів тієї чи іншої XML-схемі. При даному підході всі компоненти належать одному простору імен і, таким чином, втрачається можливість ідентифікувати в XML-документі, що "елемент A визначений у схемі X". Часто це нормально, що проектувальник не бажає категорізовивать роздільно елементи чи атрибути. У цьому випадку гомогенне простір імен цілком підходить.

      Використовуйте гетерогенне простір імен:


    • коли є кілька елементів з однаковим ім'ям (з метою запобігти колізію імен);
    • якщо є необхідність візуально ідентифікувати в XML-документі приналежність елементів і атрибутів тієї чи іншої XML-схемі. При цьому підході компоненти належать різним просторів імен, і, таким чином, існує можливість ідентифікувати в XML-документі, що "елемент A визначений у схемі X".

        І, нарешті, як було продемонстровано вище, в XML-схемах кожен компонент може бути унікально ідентифікований з використанням атрибута id (це не те ж саме, що оголосити атрибут id для елемента; це внутрішній механізм XML-схем для ідентифікації кожного компонента XML-схеми). Використання атрибуту id для ідентифікації кожного компонента XML-схеми дає навіть більший контроль над компонентом, ніж при використанні просторів імен. Комбінація цих двох засобів – просторів імен та атрибутів id компонентів XML-схем – потужний тандем, що дозволяє надійно ідентифікувати комоненти XML-схем, як візуально, так і програмно.

      • Схожі статті:


        Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

        Коментарів поки що немає.

        Ваш отзыв

        Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

        *

        *