Плох ли XML?

Вообще-то нет. Серьезно. Беда только в том, что его суют туда, куда не надо.

Сейчас объясню.

  1. Плох ли XML?
    1. К основам
    2. Языки разметки и языки представления данных
    3. Почему нельзя верстать сайты на S-expression’ах
    4. Почему нельзя писать конфиги на XML’е
    5. Почему на XML’е нельзя делать базы данных
    6. Итак, мораль
    7. Дисклеймер от автора
    8. См. также
    9. Примечания

К основам

XML — это «eXtensible Markup Language», «расширяемый язык разметки». Язык разметки (markup language) — это набор символов, вставляемых в текст для выделения отдельных частей.

Вот есть у нас текст, и мы хотим выделить, где тут заголовок, а где — цитата. Мы берем этот текст и вставляем в него его <h1> и <citation> где нам надо2.

Языки разметки и языки представления данных

Разница между ними в том, что

Почему нельзя верстать сайты на S-expression’ах

Вот мы написали такой абзац1:

Оба любят писать с ресурсов api и home. У обоих аккаунты на сервере jabber.zp.ua (проверьте сами — http://juick.com/[email protected], http://juick.com/[email protected]).

Мы хотим его немного разметить, чтобы браузер его красиво показывал. Вот так у нас получится с XHTML’ом:

<p>Оба любят писать с ресурсов <code>api</code> и <code>home</code>.
У обоих аккаунты на сервере jabber.zp.ua (проверьте сами — <a href="http://juick.com/[email protected]">1</a>,
<a href="http://juick.com/[email protected]">2</a>).</p>

А вот так получится, если мы будем использовать что-то вроде sexpr’ов:

(p
  "Оба любят писать с ресурсов"
  (code "api")
  " и "
  (code "home")
  ". У обоих аккаунты на сервере jabber.zp.ua (проверьте сами — "
  (a "http://juick.com/[email protected]" 1)
  ", "
  (a "http://juick.com/[email protected]" 2)
  ").")

Чтобы не выглядело так страшно, можно убрать идентацию:

(p "Оба любят писать с ресурсов" (code "api") " и " (code "home")
". У обоих аккаунты на сервере jabber.zp.ua (проверьте сами — " (a "http://juick.com/[email protected]" 1) ", "
(a "http://juick.com/[email protected]" 2) ").")

Выглядит ужасно. XHTML даже с длинными тегами смотрится как текст со вставками разметки, а вот sexpr’овый вариант напоминает программный код, который целиком не прочитаешь. Особенно отрываются от текста знаки препинания и пробелы — не поймешь, правильно они расставлены или нет. Все это, конечно, субъективно, но я думаю, что в этом примере вы не будете со мной спорить.

Плюс к этому следует добавить, что в случае с XHTML поломанный тег внутри другого тега (например, <p><br</p>) не натворит ничего страшного вне родительского тега, а в случае с sexpr’ами неправильно поставленная кавычка (которыми изобилует текст) рискует поломать весь документ. Это будет сущим адом.

Почему нельзя писать конфиги на XML’е

Начнем с простого. Выдуманный пример на XML:

<outgoing rate="monthly">
  <price>30.</price>
  <name>Internet</name>
</outgoing>

И он же — но для s-expressions:

(outgoing
  (rate monthly)
  (price 30.)
  (name "Internet"))

Избыточность XML’а сразу бросается в глаза. За тегами данных не видно. Ну а что вы хотите — это не текст, который надо размечать.

При написании такого конфига выводит из себя необходимость заканчивать строки закрывающими тегами. В конфиге хочется нажать клавишу «enter» и закончить таким образом строку. В случае XHTML’а вопроса «зачем ставить закрывающий тег?» не возникало, так как текст нужно размечать со всеми его пробелами и переносами строк, которые убирать нельзя.

Ладно, идем дальше. Слева — боевой конфиг icecast’а. Справа — он же, но на языке представления данных.

<!-- This config file contains a minimal set of configurable parameters,
     and mostly just contains the things you need to change.  We created
     this for those who got scared away from the rather large and heavily
     commented icecast.xml.dist file. -->
<icecast>
    <limits>
        <sources>2</sources>
    </limits>
    <authentication>
        <source-password>sdgfsdfgdsfg</source-password>
        <relay-password>wrwefwfw</relay-password>
        <admin-user>ghff</admin-user>
        <admin-password>666</admin-password>
    </authentication>
    <directory>
        <yp-url-timeout>15</yp-url-timeout>
        <yp-url>http://dir.xiph.org/cgi-bin/yp-cgi</yp-url>
    </directory>
    <hostname>localhost</hostname>
    <listen-socket>
        <port>8000</port>
    </listen-socket>
    <fileserve>1</fileserve>
    <paths>
        <logdir>/var/log/icecast2</logdir>
        <webroot>/usr/share/icecast2/web</webroot>
        <adminroot>/usr/share/icecast2/admin</adminroot>
        <alias source="/" dest="/status.xsl"/>
    </paths>
    <logging>
        <accesslog>access.log</accesslog>
        <errorlog>error.log</errorlog>
        <loglevel>3</loglevel> <!-- 4 Debug, 3 Info, 2 Warn, 1 Error -->
    </logging>
</icecast>

# This config file contains a minimal set of configurable parameters,
#      and mostly just contains the things you need to change.  We created
#      this for those who got scared away from the rather large and heavily
#      commented icecast.xml.dist file.

limits:
  sources: 2

authentication:
  source-password: "sdgfsdfgdsfg"
  relay-password: "wrwefwfw"
  admin-user: "ghff"
  admin-password: "666"

directory:
  yp-url-timeout: 15
  yp-url: "http://dir.xiph.org/cgi-bin/yp-cgi"

hostname: "localhost"

listen-socket:
  port: 8000

fileserve: 1

paths:
  logdir: "/var/log/icecast2"
  webroot: "/usr/share/icecast2/web"
  adminroot: "/usr/share/icecast2/admin"
  alias:
    source: /
    dest: status.xsl

logging:
  accesslog: "access.log"
  errorlog: "error.log"
  loglevel: 3  # 4 Debug, 3 Info, 2 Warn, 1 Error

Справа не придуманный мною на коленке формат. Это YAML. Вы можете подключить библиотеку для работы с yaml’ом и парсить такие конфиги так же легко, как и XML’овые.

Удивительно, но иногда конфиги на XML бывают почти так же трудночитаемыми, как и исходный код программы. Вот это из openbox’а. Чтобы забиндить там клавишу, нужно написать что-то вроде:

<keybind key="A-F4">
  <action name="Close"/>
</keybind>

А это из моего конфига xmonad’а, на чистом хаскелле:

-- close focused window
, ((modMask .|. shiftMask, xK_c     ), kill)

Почему на XML’е нельзя делать базы данных

Про это написал Joel Spolsky еще десять лет назад:

Как реляционная база данных выполняет команду SELECT author FROM books? В реляционной базе данных каждая строка в таблице (например, в таблице books) имеет одинаковую длину в байтах, и каждое поле находится по фиксированному смещению относительно начала строки. Так что, например, если каждая запись в таблице books имеет длину 100 байт, и поле author находится по смещению 23, то имена авторов расположены начиная с байтов 23, 123, 223, 323, и т.д. Как выглядит код перехода на следующую запись? Примерно так:

pointer += 100;

Одна инструкция процессора. Ну очень быстро.

Теперь посмотрим на ту же таблицу в XML.

<?xml blah blah>
<books>
    <book>
        <title>UI Design for Programmers</title>
        <author>Joel Spolsky</author>
    </book>
    <book>
        <title>The Chop Suey Club</title>
        <author>Bruce Weber</author>
    </book>
</books>

Вопрос. Как выглядит код перехода на следующую запись?

Ээээ..

Итак, мораль

Просто? Очень просто!

И не надо пихать технологию в код только потому, что она «крутая» и «модная». А скорее всего потому, что вы ничего другого не освоили. Или не хотите разобраться в предметной области. Нужен конфиг для программы? Будете делать его на XML’е? Вот зачем?

Причем не важно вообще, что это за технология. Я встречал программистов, которые пихали не к месту не только XML и PHP, но и даже LaTeX. Опыт растет, а критерии выбора инструмента остаются теми же: «то, чем все пацаны на районе пользуются».

Дисклеймер от автора

Я ненавижу XML. Сложно вспомнить другую технологию, которая бы столько раз выводила меня из себя. Но мне так же сложно указать на недостатки XML’а в пределах его ниши. Все случаи «плохого XML’а» были связаны только с неправильным его использованием.

А разгадка одна: программисты — идиоты.

См. также

Примечания

1 Этот абзац взят из статьи про Антона Угнича

2 Дается эта возможность, правда, ценой того, что текст, похожий на XML-теги, придется эскейпить. Ну, по меньшей мере заменять < на &lt; — обычно этого бывает достаточно. Плохо, конечно, но другие способы отделения разметки от текста бывают еще хуже3, а языки разметки, в которых эскейпинг не предусмотрен, можно замучаться парсить4.

3 Об использовании разделителей хорошо написал Voker57 в своей статье «Delimeters Must Die».

4 Пример языка разметки, в котором «все настолько просто, что не нужно ни о чем думать» — textile. Вообще, язык получается таким, что некоторые вещи на нем невозможно написать. Свои мучения в его реализации я изложил отдельно.