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

Журнал ВРМ World

Практическая работа с XML: опыт безопасного написания документов и приложений

Как избежать распространенных ошибок в работе с XML

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

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

Когда XML был представлен публике впервые, организации и разработчики отнеслись к этому новому языку разметки с вежливым подозрением. Но по мере того как они использовали этот язык для решения все большего числа проблем, подозрительность сменилась энтузиазмом. Сегодня уже очень многие разработчики и организации используют XML в своих проектах.

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

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

Автор выражает уверенность в том, что его опыт в решении часто возникающих проблем поможет читателям избежать этих ошибок.

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

  • использование парсеров и управляющие последовательности для зарезервированных символов;
  • кодировка;
  • пространства имен.

Простой синтаксис

В первом разделе обсуждаются некоторые общие вопросы синтаксиса XML.

Синтаксис XML достаточно простой: просто необходимо соблюдать баланс между открывающими и закрывающими тэгами. Тем не менее автор очень хотел бы получать знаменитый пятицентовик всякий раз получая электронное письмо, отправитель которого сетует на то, что ему не удалось обработать прилагаемый к письму документ XML ни одним из известных ему парсеров. Неизменно при открытии присланного документа XML автор обнаруживает очевидную синтаксическую ошибку - пустой тэг без закрывающей косой черты (например: <empty/>). Если в документе не соблюдаются все правила синтаксиса XML, то он не является документом XML и, значит, не может быть обработан с помощью инструментов XML. Синтаксис XML очень точный и формальный. Все очень просто: либо в документе соблюдаются все правила синтаксиса XML, либо он не может быть распознан как документ XML.

Но некоторые приложения могут отказываться работать с абсолютно точно допустимыми документами. Такие приложения могут реализовывать синтаксис XML не полностью и, соответственно, быть неспособным распознать некоторые символьные сущности (например, i).

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

Решения и исправления

К счастью, всех этих проблем можно полностью избежать, используя парсер XML. Парсеры XML доступны во всех языках программирования (даже Cobol поддерживает XML), поэтому их безусловно стоит использовать.

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

Если такой тщательный контроль, который обеспечивает парсер, не требуется, то компонент преобразования (такой как JAXB, Castor или Axis) может оказаться удобнее. Эти компоненты напрямую преобразуют тэги XML в объекты JavaTM. JAXB и Castor работают с документами в файлах, а Axis - с web-сервисами. Компоненты преобразования включают парсер XML, поэтому они полностью поддерживают синтаксис XML.

Хотя автор рекомендует использовать парсеры для чтения документов XML, он также признает, что этого можно избежать, если пользователь создает собственный способ для записи документов. Чтение документов XML - достаточно сложная задача, поскольку читающее программное обеспечение должно поддерживать полный синтаксис XML. Напротив, создание документов XML - это сравнительно более легкая процедура, поскольку можно использовать только часть синтаксических возможностей. Например, если пользователю не требуются атрибуты, то и не возникает необходимости в их поддержке; если не нужно многожество кодировок, то их также можно не поддерживать, и т.д.

Единственная опасность в этом подходе - это то, что нужно корректно передавать зарезервированные символы (см. табл. 1). Особое внимание нужно обращать на символы сущностей (например, i), поскольку они зависят от кодировки документа (см. раздел "Проблемы кодировки" ниже).

Таблица 1. Зарезервированные символы

Символ
Управляющая последовательность
Примечания
< <
& &
> >
' ' Только в атрибутах, если символ " используется как разделитель
" " Только в атрибутах, если символ ' используется как разделитель
другие &#unicode; Любой символ, не поддерживаемый данной кодировкой

Обычно достаточно простого цикла, аналогичного приведенному в листинге 1. Данную функцию можно применять более эффективно, но листинг 1 синтаксически корректен, если документ создается для потока UTF-8 или UTF-16 (в противном случае необходимо также передать некоторые символы за счет использования символьных сущностей).

Листинг 1. Применение стандартного алгоритма избегания


// assumes UTF-8 or UTF-16 as encoding,
public String escape(String content)
{ 
        StringBuffer buffer = new StringBuffer(); 
        for(int i = 0;i < content.length();i++) 
        { 
                    char c = content.charAt(i); 
                    if(c == '<')
                               buffer.append("<"); 
                    else if(c == '>') 
                               buffer.append(">"); 
                    else if(c == '&')
                               buffer.append("&"); 
                    else if(c == '"') 
                               buffer.append("""); 
                    else if(c == '\'') 
                               buffer.append("'"); 
                    else 
                               buffer.append(c);
        } 
        return buffer.toString(); 
}


Некоторые разработчики предпочитают использовать секции CDATA вместо управляющей последовательности. CDATA - это механизм, который показывает, что часть документа может содержать незаменяемые зарезервированные символы. Например: <condition>< ! [CDATA [a > 4] ] > < / condition>. Этот способ менее надежен, чем управляющая последовательность, т.к. одна секция CDATA не может включать другую такую же секцию.

В качестве еще одного решения автор рекомендует преобразователь (transformer), для чего предлагает познакомиться со своей статьей "Реализация XMLReader" (Implement XMLReader).

Еще один способ исправлений

Представим ситуацию, что пользователю необходимо работать с приложением, которое не совсем соответствует синтаксису XML, и он не может убедить разработчика исправить это приложение.

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

Проблемы кодировки

Более серьезные проблемы могут возникнуть при использовании различных кодировок. Разработчики часто упускают из виду тот факт, что кодировки не ограничивают тот набор символов, который поддерживает XML. Любой документ XML поддерживает полный набор символов Unicode (16- или 32-битные символы в XML 1.1).

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

Это действительно проблема, поскольку если приложения Java или последняя версия DB2® могут поддерживать Unicode, то более ранние приложения почти не способны на это. Таким образом, если документ XML передается в "старое" приложение, придется столкнуться с Unicode. Соответственно, использование кодировок не является решением, поскольку, как показано выше, всегда можно избежать специальных символов за счет символьных сущностей.

Поскольку переписывание старого приложения редко используется как решение проблемы, необходим способ конвертирования, который превратит символы Unicode в набор, приемлемый для приложения: например, конвертирование i в обычную i (т.е. убирание диакритического знака). Большинство парсеров XML имеют возможности для обработки символов Unicode.

Проблемы пространства имен

Третий источник проблем, который обсуждается в настоящей статье, - это использование пространств имен XML.

Пространства имен были введены для управления словарями XML и предотвращения использования тэгов с одинаковыми именами. Часто два словаря могут использовать один и тот же тэг в разных контекстах. Например, в словаре сообщений могут быть тэги для темы, даты, отправителя, адресата и тела письма (см. листинг 2), а в словаре цифровых ресурсов - тэги для темы, даты, описания, камеры и номера кадра (см. листинг 3).

Листинг 2. Словарь сообщений


<envelope> 
        <subject>Test memo</subject>
        <date>April 26, 2005</date> 
        <from>jack@writeit.com</from> 
        <to>john@xmli.com</to> 
        <body>memo body goes here</body>
</envelope>


Листинг 3. Словарь цифровых ресурсов


<photo>
        <subject>Westlicht Museum of Camera and Photography, Vienna</subject> 
        <date>April 25, 2005</date> 
        <description>Lobby of the museum</description> 
        <camera>Nikon D70</camera>
        <frame>5643</frame> 
</photo>


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

Пространства имен XML превращают локальные имена в глобальные путем добавления глобального идентификатора к имени тэга. Для того чтобы гарантировать уникальность глобальных идентификаторов, они должны представлять собой URI (Uniform Resource Identifiers - универсальные идентификаторы ресурсов) (т.е. содержать имя домена, зарегистрированного для гарантии уникальности). Соответствующий пример приведен в листинге 4.


Листинг 4. Сочетание словарей


<env:envelope xmlns:env="http://psol.com/2005/env"
                                         xmlns:ph="http://psol.com/2005/photo">
        <env:subject>Latest photo</env:subject>
        <env:date>April 27, 2005</env:date>
        <env:from>jack@writeit.com</env:from>
        <env:to>john@xmli.com</env:to>
        <env:body>
                <ph:photo>
                        <ph:subject>Westlicht Museum
                                of Camera and Photography, Vienna</ph:subject>
                        <ph:date>April 25, 2005</ph:date>
                        <ph:description>Lobby of the museum</ph:description>
                <ph:camera>Nikon D70</ph:camera>
                        <ph:frame>5643</ph:frame>
                 </ph:photo></env:body>
</env:envelope>


Здесь есть два момента, которые требуют дополнительных пояснений:

  • URI - это идентификатор, а не адрес;
  • префикс - это не идентификатор.

URI и адреса

Хотя на практике большинство URI являются адресами (URL - Uniform Resource Locators - унифицированные указатели информационных ресурсов), в пространствах имен XML они используются только как идентификаторы. К сожалению, пространства имен не могут идентифицироваться так же, как пакеты Java. Например: com.psol.vocabulary вместо более неопределенного http://psol.com/vocabulary.

Поскольку URI являются идентификаторами, адреса могут не работать, т.е. выдавать ошибку 404 - ресурс не найден - при попытке открыть их. Но они выполняют требуемые от них функции. И, вопреки широко распространенному заблуждению, URI пространств имен не указывают на схему XML Консорциума всемирной сети (World Wide Web Consortium - W3C).

Во-вторых, поскольку в этом контексте URI являются идентификаторами, приложение должно точно, до буквы, соответствовать их написанию. Было бы ошибкой использовать URI словаря XML для указания, например, на свой сервер. Например, URI для XSL выглядит следующим образом: http://www.w3.org/1999/XSL/Transform. Если пользователь работает в IBM, он не может превратить этот URI в, например, такой: http://www.ibm.com/1999/XSL/Transform. На самом деле изменения URI существующих словарей не допускаются вообще.

Когда автор проводил занятия, посвященные XSLT, слушатели часто недоумевали, почему процессор XSLT не работает - на самом деле, причина была только в том, что XSLT URI не был указан с ошибкой.

Первый вывод из вышеизложенного материала - необходимо воздерживаться от изменения пространств имен. Включение схемы версии в URI обычно не является хорошей идеей, поскольку это наверняка "сломает" приложения при выполнении обновлений.

Префиксы

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

Примеры неправильного и правильного кодов приведены в листингах 5 и 6, соответственно.


Листинг 5. Некорректная проверка префиксов


startElement(String uri,String local,String qname,Attributes atts) 
{
         if(qname.equals("env:Envelope")) 
                ; // do something
}


Листинг 6. Корректная проверка URI пространства имени


startElement(String uri,String local,String qname,Attributes atts) 
{
         if(uri.equals("http://psol.com/2005/envelope") 
                && local.equals("Envelope"))
                 ; // do something
}


Заключение

Итак, если пользователь знает обо всех потенциальных опасностях и ошибках, описанных выше, то он может существенно улучшить создаваемые им документы и приложения XML. Более того, это дает возможность свести к минимуму риск несовместимости и заметно упростить поддержку приложений XML.

Ресурсы

  1. Дискуссионный форум (discussion forum).
  2. Статья Бенуа Маршаля о реализации XMLReader (Implement XMLReader).
  3. Вводное пособие по работе с программными интерфейсами приложений Java (Data binding with JAXB).
  4. Альтернативные способы привязки данных в Java (Data binding with Castor).
  5. Использование парсера SAX и сравнение событийно-ориентированных и объектно-ориентированных API (SAX, the power API).
  6. Кодировки Unicode (Forms of Unicode).
  7. Статья о проблемах пространств имен XML (Use XML namespaces with care).
  8. Другие статьи Бенуа Маршаля в рубрике "Практическая работа с XML" (Working XML).
  9. Дополнительные ресурсы по XML (developerWorks XML zone).
  10. Книги по XML (Developer Bookstore).
  11. Информация о том, как стать Сертифицированным разработчиком IBM в области XML и других смежных технологий (IBM Certified Developer in XML and related technologies).

Об авторе

Бёнуа Маршаль (Benoit Marchal) - бельгийский консультант. Он автор многих книг, посвященных XML, в том числе "XML на примерах, второе издание" (XML by Example, Second Edition). С ним можно связаться по адресу bmarchal@pineapplesoft.com или с помощью его сайта www.marchal.com.