XML — это достаточно просто. Если хорошо поискать, то в нём можно найти достаточно много сложных вещей — таких, как валидация, преобразования и запросы. Но в основе поразительно огромного числа проектов лежат всего лишь синтаксически корректные комбинации элементов и атрибутов.
Недавно я столкнулся с шаблоном (а скорее, даже анти-шаблоном), который угрожает всему тому, на чём построены наши проекты. Он вреден, и его необходимо искоренить.
Поначалу не было очевидным, что идея синтаксически корректной разметки — драконовский подход к обнаружению ошибок, которого требует Рекомендация XML 1.0 — приживётся. По крайней мере, мне это не было очевидным — я не берусь говорить за остальных.
Технические преимущества синтаксической корректности очевидны: она позволяет парсеру просто и однозначно определить логическую структуру XML-документа. XML пришёл на смену SGML — языку с кучей правил для сокращения объёма разметки. Из-за всех этих правил написать парсер для SGML было тяжело — причём очень тяжело. Ещё у SGML был «двоюродный брат» — HTML. Большая часть HTML-документов не удовлетворяла даже правилам SGML; чтобы обрабатывать HTML, приложениям приходилось — кроме всей сложности работы с SGML — изобретать на ходу собственные правила обработки некорректной разметки.
У всех этих языков, кошмарных с точки зрения написания парсеров и неоднозначности разметки, было одно преимущество: разметка документов вручную была чрезвычайно проста. SGML позволял не заключать значения атрибутов в кавычки, опускать открывающие или закрывающие теги, и — при желании — пользоваться чудным мини-языком SHORTREF. HTML позволял загрузить в браузер практически любую мешанину тегов — и браузер показывал нечто осмысленное. Если чуть-чуть поколдовать над этой мешаниной тегов, то можно было даже получить результат, который — в некоторых браузерах — соответствовал задуманному.
XML объявил: «Не пойдёт. Слишком тяжело, слишком дорого, слишком сложно. Ваша разметка должна выглядеть вот таким вот образом — практически без сокращений. И если хоть что-то в ней будет неверно, то приложения не имеют права каким-либо образом обрабатывать ваши ошибки. Если документ синтаксически некорректен, то это не XML.»
Тогда мы все на минутку затаили дыхание.
Время шло. Нужные компании объявили о поддержке XML; влиятельные представители сообщества пользователей представили себе открывающиеся возможности, когда они сами с лёгкостью смогут писать самые мощные приложения, и согласились, что необходимое для этого усложнение разметки обоснованно. XML преодолел первый — пожалуй, самый важный — барьер: он был замечен.
Теперь, через несколько лет, мы всё больше и больше страдаем. Каждый из нас уже может указать на тот или другой пункт спецификации и с уверенностью заявить, что будь его воля, он всё бы сделал по-другому, и притом куда лучше. Но думаю, многие всё же согласятся, что XML в целом оказался успешной затеей — ведь теперь в нашем распоряжении есть поразительно огромное число мощных, гибких и удобных инструментов.
И всё это благодаря тому, что XML-документы обязаны быть синтаксически корректными.
Поэтому я был удивлён, когда обнаружил в RSS поддержку определённого рода экранированной разметки. RSS обычно используется блоггерами для публикации списка своих новых заметок, и сайтами новостей для публикации обзоров свежих статей — хотя, как и большинство XML-технологий, RSS достаточно гибок, и для обзора всей широты его возможностей мне не хватило бы здесь места.
Моё удивление сменилось недоумением, когда я узнал, что разработчики новой версии RSS не собираются исключать из него этот безобразный хак. Когда же я узнал, что этот хак проник в другой XML-язык — FOAF — то моё недоумение сменилось крайней озабоченностью.
Экранированная разметка — это разметка, которая «экранирована» так, что разметкой больше не является. Если вы писали XML-документы, где текст содержал в себе угловые скобки или амперсанды, то вы уже понимаете, о чём идёт речь.
В RSS экранированная разметка обычно выглядит так:
<description><![CDATA[
Some description of an article about
<a href="http://www.w3.org/TR/REC-xml">XML</a> that
contains a link and a <br> element.]]>
</description>
Важно понимать, что этот пример мог бы быть записан и по-другому:
<description>
Some description of an article about
<a href="http://www.w3.org/TR/REC-xml">XML</a> that
contains a link and a <br> element.
</description>
Не стоит думать, что использование элемента CDATA придаёт экранированной разметке какое-то особое смысловое значение. Хотя технически приложения способны определить, какой именно способ использовался для экранирования разметки, XML не допускает придание этим способам различного смысла. Экранирование при помощи CDATA равноправно с любым другим способом экранирования разметки.
Безусловно, нет ничего плохого, если экранированная разметка используется именно для экранирования разметки. В этом случае пример выше отобразился бы так:
Some description of an article about <a href="http://www.w3.org/TR/REC-xml">XML</a> that contains a link and a <br /> element.
Но по совершенно непостижимым причинам большинство RSS-клиентов отобразит его так:
Some description of an article about XML that contains a link and a
element.
Существуют полуформальные соглашения о том, что содержимое некоторых — или даже всех — элементов RSS перед отображением «разэкранируется». Это жутким образом разрушает всю стройную систему разметки, возрождая то, от чего XML стремился уйти.
По-видимому, есть два аргумента в защиту экранированной разметки:
Агрегаторы используют средства XML для объединения данных из нескольких RSS-источников («фидов»). Агрегаторы — это программы либо сайты, которые могут составлять для нескольких источников единый RSS-фид. Можно, например, подписаться на фид, отображающий последние десять новостей, переданные выбранными вами агентствами.
Эти агрегаторы утверждают, что они используют XML лишь в качестве протокола передачи и никак не обрабатывают само содержимое фидов. Фиды-источники могут быть синтаксически корректными, а могут не быть, — и этим исчерпывается анализ разметки фида агрегатором. Раз агрегаторам совершенно безразлично содержимое фидов, то проще и эффективнее — так они утверждают — хранить это содержимое в виде текстовых блоков неопределённой структуры, и переложить анализ этих блоков на плечи программы-клиента.
Я не думаю, что эти аргументы сколько-нибудь оправдывают выбранную агрегаторами стратегию:
Экранирования разметки, особенно при помощи секций CDATA, недостаточно, чтобы получился синтаксически корректный XML-документ. Есть и другие вещи, способные нарушить синтаксическую корректность: запрещённые символы Unicode, проблемы кодировки для допустимых символов Unicode, запрещённые последовательности символов (такие как «[[>») и т.д. Не говоря уже о том, что вложенные секции CDATA недопустимы.
Есть более простые способы экранирования содержимого. Прежде всего, если само это содержимое — синтаксически корректный XML, то не требуется никакого экранирования. Если это не синтаксически корректный XML, то скорее всего, это HTML. Даже и в этом случае запрещено выдавать за XML документ, не являющийся синтаксически корректным. Известно много способов преобразовать HTML-документ в XHTML (или даже просто в синтаксически корректный XML). Самый простой из этих способов — полное отбрасывание всей HTML-разметки — и то лучше, чем «решение» с экранированием разметки.
Ещё меньшего доверия заслуживает аргумент о неопределённой структуре текстовых блоков. Одно лишь то, что некоторым агрегаторам безразлично содержимое их фидов, не оправдывает запечатывание этого содержимого в чёрный ящик, который ни одно нормальное XML-приложение не в состоянии открыть.
Если так уж необходимо экранировать содержимое, если слишком непрактично преобразовывать его в синтаксически корректный XML либо слишком накладно обрабатывать его вложенную разметку — тогда кодируйте содержимое в base64.
Тогда вы получите сразу два явных преимущества: во-первых, правильно будут обрабатываться любые символы в содержимом — так что этот метод действительно будет работать, а это никогда не лишнее. Во-вторых, всем станет ясно, что этот формат не предназначен для обработки вручную.
Думаю, самая большая опасность, которую представляет вся эта неуклюжая затея с экранированием разметки, — это подстрекательство наивных программистов к перенятию такого стиля работы с XML для их собственных приложений.
Экранирование разметки позволяет помещать HTML-код и другую разметку внутрь элементов, в которых XML-схема или DTD допускает только простой текст.
Извините, но очевидный, неопровержимый и весьма существенный аргумент против использования экранированной разметки заключается именно в том, что она позволяет помещать HTML-код и другую разметку внутрь элементов, в которых XML-схема или DTD допускает только простой текст.
Сама идея экранированной разметки идёт вразрез с основами XML. Если этот хак разойдётся из RSS по другим XML-языкам, то очень скоро мы вновь окажемся в трясине из поощряющей ошибки мешанины тегов — там, откуда мы с таким трудом выбирались.
А похоже, что этот хак уже расходится. Не так давно вопрос экранированной разметки всплыл в контексте FOAF. Спецификация FOAF не допускает никаких подобных хаков, но одна из программ для блоггеров, генерирующая FOAF, после вставки пользователем HTML-кода в элемент «bio» экранировала в нём всю разметку. Фирму-разработчика этой программы быстро удалось убедить исправить этот баг.
Совершенно ясно, что шаблон экранированной разметки разойдётся по XML-языкам, если это не пресечь. Если не удастся остановить его вовремя, то он станет стандартом де-факто, и разработчики будут вынуждены продолжать поддержку этой мерзости из простых экономических соображений. И виноваты будут не они, а все мы — в том, что не убили вирус до того, как он заразил всё вокруг.