Консалтинг и автоматизация в области управления
эффективностью банковского бизнеса

Журнал ВРМ World

SOAP-кодирование, типы WSDL и XML Schema

Использование Web-службы подразумевает обмен хотя бы одним XML-сообщением между отправителем и получателем. Формат сообщения должен быть определен так, чтобы отправитель мог формировать, а получатель обрабатывать сообщение. Формат любого сообщения включает общую структуру дерева (tree), локальное имя и имя пространства имен для элементов и атрибутов, используемых в этом дереве, а также типы этих элементов и атрибутов.

Имя и типы элементов и атрибутов, содержащихся в этом сообщении, могут быть определены в схеме. Именно так язык описания Web-служб (Web Services Description Language, сокр. WSDL) может использовать схему. Если описание Web-службы на WSDL располагается в начальной точке, формат сообщения известен еще до того, как написана хотя бы строчка кода. Однако, во многих случаях код, который будет использоваться как Web-служба, уже написан. Или же разработчики не торопятся начинать с WSDL, предпочитая программную структуру данных. Но даже в этих случаях для того, чтобы клиент правильно создавал запросы и деструктурировал ответы, необходимо некоторое описание Web-службы. В идеале им мог бы быть сам WSDL, поскольку в противном случае клиентам пришлось бы изучать и разбираться в многочисленных языках описания.

Таким образом, если схема или связанный с ней WSDL не располагаются в начальной точке, возникает вопрос: как же WSDL будет сгенерирован, и какой формат будет у XML-сообщения? Можно утверждать, что многие существующие реализации SOAP включат программный тип данных, а именно какое-нибудь описание класса, и запишут (serialize) этот тип в XML. Но если схема отсутствует, каким образом эти реализации определят, что использовать: элементы или атрибуты? По какому принципу они дадут имена этим конструкциям, и какой должна быть общая структура дерева? Ответы на эти вопросы могут быть найдены во второй части спецификации SOAP 1.2 (SOAP 1.2 specification, Part 2), в подразделе SOAP-кодирование (SOAP Encoding).

SOAP-кодирование

SOAP-кодирование устанавливает ряд правил преобразования программных типов в XML. Оно включает требования к преобразованию сложных структур данных, типов массивов и ссылочных типов. В отношении сложных структур данных применяемый подход оправданно прямолинеен; так, все данные записываются как элементы, а имя любого заданного элемента соответствует имени поля данных в программном типе. Например, при задании следующего класса Java,

    class Person
    {
        String name;
        float age;
    }

поля name и age были бы записаны с использованием элементов, с локальными именами name и age, соответственно. Оба элемента были бы неквалифицированными, т.е., имя пространства имен было бы пустым. Для тех случаев, когда имя поля не было бы разрешенным XML-именем, в Приложении А (Appendix A) спецификации SOAP можно найти алгоритм преобразования.

Преобразование ссылочных типов - более сложная задача. Для этого потребуется преобразовать экземпляр (instance) и пометить его неквалифицированным атрибутом с локальным именем id. Значению href соответствует URI, который ссылается на соответствующий записанный экземпляр через его id-атрибут. Этот метод позволяет записывать в XML графы, включая циклические графы (cyclic graph).

Преобразование типов

SOAP-кодирование позволяет также преобразовывать программные типы данных в типы данных, описанные во второй части спецификации, "Типы данных" (XML Schema Part 2: Datatypes). Таким образом, при задании программной структуры могут быть определены имя и тип каждого элемента в записанном XML. Многие считают, что SOAP-кодирование в равной степени регламентирует как преобразование между системами типов, так и между форматами экземпляров.

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


<soap:Envelope xmlns:soap=
"http://www.w3.org/2001/12/soap-envelope">
 <soap:Body>
  <pre:Add xmlns:pre="http://example.org/lists"

soap:encodingStyle=
"http://www.w3.org/2001/12/soap-encoding" >
   <person>
  <  name>Hayley</name>
  <  age>30</age>
   </person>
  </pre:Add>
 </soap:Body>
</soap:Envelope>


Значение атрибута encodingStyle показывает, что запись данных выполнялась в соответствии с правилами SOAP-кодирования. Благодаря этому считыватель (deserializer) на другом конце "трубы" корректно расшифрует сообщение. С SOAP могут использоваться и другие стили кодирования, в этом случае атрибут encodingStyle имел бы другое значение URI.

Приведение типов

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

В некоторых случаях точная информация о типе может быть не известна вплоть до момента выполнения. Например, когда Web-служба принимает данные тем же способом, как VARIANT в COM, any в CORBA или Object в Java. Такая служба не определяет тип во время проектирования. Эта информация должна быть предоставлена во время выполнения. Подобные службы на самом деле не принимают абсолютно никакого типа, а работают на довольно маленьком подмножестве типов, генерируя ошибки при встрече с неизвестным типом.

Наконец, информация может отсутствовать, когда образуются дополнительные классы, например, RacingDriver и FootballPlayer из Person. Если бы Web-служба понимала эти классы, они могли бы войти в отправляемые запросы.

В обоих случаях: и "полностью" полиморфного элемента и в более специфичном случае явно производных типов, имени элемента уже недостаточно для того, чтобы полностью распознать тип элемента. Для этого требуется кое-что еще.

Правила SOAP-кодирования позволяют использовать атрибут type из пространства имен http://www.w3.org/2001/XMLSchema-instance, чтобы установить, что во время выполнения используется определенный тип. Тогда элемент person в сообщении будет выглядеть следующим образом:


<person xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
     xsi:type="RacingDriver" >
  <name>Martin</name>
  <age>34</age>
  <bestplace>6th</bestplace>
</person>


Следует отметить, что атрибут xsi:type относится к классу QName. Следовательно, строго говоря, этот пример ссылается на неопределенный тип RacingDriver. На практике, чтобы избежать конфликта имен, пространству имен нужно назначить тип. Кроме того, атрибут xsi:type нужен только тогда, когда точный тип не известен до момента выполнения. В большинстве случаев, когда обе стороны заранее знают типы, xsi:type является избыточным.

Заключение

Когда бы ни посылались сообщения, все-таки некоторая информация о типах известна заранее. В одних случаях, досконально известны все типы, и тогда вполне достаточно знать имена элементов. В других случаях более конкретная информация о типах может быть передана во время выполнения. В таких случаях используется атрибут xsi:type, а типы должны быть соотнесены с пространствами имен.

Может показаться, что определив форматы сообщений для обмена заданной Web-службой, мы фактически определяем схему для этих форматов. Следовательно, SOAP-кодирование на самом деле осуществляет преобразование из систем программных типов в систему XML-типа, т.е., XML Schema. Часть типов преобразуется прекрасно; другая, например, ссылки, по причине древовидной природы XML преобразуются не столь хорошо. При условии, что формат преобразования - XML, а XML - дерево, необходимо серьезно задуматься над тем, стоит ли напрямую моделировать в SOAP более сложные конструкции, такие как ссылки. Если эти конструкции действительно нужны, необходимо вооружиться удобным подходом XML Schema.