XML
XML за 10 минут: структура документа, элементы, атрибуты, CDATA, сущности, пространства имён, well-formed и практический пример конфига.
XML (eXtensible Markup Language) — текстовый формат для хранения и передачи структурированных данных в виде дерева помеченных элементов. Он не описывает внешний вид (как HTML), а описывает смысл и структуру данных. Этот экспресс-тур — вся азбука XML на одной странице через плотно закомментированный код.
Что такое XML и общая структура
Документ XML — это дерево элементов с единственным корнем. Часто начинается с декларации (пролога).
<?xml version="1.0" encoding="UTF-8"?>
<!-- Это декларация XML: версия и кодировка. Необязательна, но рекомендуется. -->
<!-- Так выглядит комментарий: его текст игнорируется парсером. -->
<!-- Ниже корневой элемент: ровно один на весь документ -->
<library>
<book>
<title>Война и мир</title>
<author>Толстой</author>
</book>
</library>
<!-- Документ = пролог + ровно один корневой элемент (дерево). -->
Элементы и теги
Элемент состоит из открывающего тега, содержимого и закрывающего тега. Бывают пустые элементы.
<!-- Открывающий тег <title> ... закрывающий тег </title> -->
<title>Привет, XML</title>
<!-- Вложенность: элементы образуют дерево, теги не должны пересекаться -->
<person>
<name>Анна</name>
<city>Москва</city>
</person>
<!-- Пустой элемент можно записать двумя способами: -->
<line></line> <!-- открыли и сразу закрыли -->
<line/> <!-- самозакрывающийся тег (то же самое) -->
<!-- Имена тегов чувствительны к регистру: <Name> и <name> РАЗНЫЕ -->
Атрибуты
Атрибуты задаются внутри открывающего тега в формате name="value". Значение всегда в кавычках.
<!-- Атрибуты id и lang у элемента book -->
<book id="42" lang="ru">
<title>XML за 10 минут</title>
</book>
<!-- Можно одинарные или двойные кавычки, но кавычки ОБЯЗАТЕЛЬНЫ -->
<item name='чай' qty="3"/>
<!-- Один атрибут не может повторяться в одном теге: -->
<!-- <book id="1" id="2"/> <- ОШИБКА, дубль атрибута -->
Корневой элемент и иерархия
В документе ровно один корневой (родительский для всех) элемент. Остальные вложены в него.
<!-- <catalog> — корень. Внутри потомки, у потомков свои потомки. -->
<catalog>
<product> <!-- ребёнок корня -->
<name>Клавиатура</name> <!-- внук корня -->
<price>2990</price>
</product>
<product>
<name>Мышь</name>
<price>1490</price>
</product>
</catalog>
<!-- ДВА корня на верхнем уровне запрещены — только один. -->
Текст и CDATA
Если внутри текста нужны символы вроде < или & без экранирования, оборачивают в секцию CDATA.
<!-- Обычный текстовый узел внутри элемента -->
<message>Просто текст</message>
<!-- CDATA: всё внутри воспринимается буквально, как есть -->
<code>
<![CDATA[
if (a < b && b > 0) { ok(); }
]]>
</code>
<!-- Внутри <![CDATA[ ... ]]> символы < и & НЕ нужно экранировать. -->
<!-- Единственное, что нельзя писать внутри CDATA — последовательность ]]> -->
Сущности (entities)
Спецсимволы заменяются именованными сущностями. Сущность начинается с & и заканчивается точкой с запятой.
<!-- 5 встроенных сущностей XML: -->
<!-- &lt; даёт символ < (меньше) -->
<!-- &gt; даёт символ > (больше) -->
<!-- &amp; даёт символ & (амперсанд) -->
<!-- &quot; даёт символ " (кавычка) -->
<!-- &apos; даёт символ ' (апостроф) -->
<formula>1 &lt; 2 &amp;&amp; 3 &gt; 2</formula>
<!-- В тексте выше парсер прочитает: 1 < 2 && 3 > 2 -->
<!-- Числовая ссылка: &#169; — знак ©, &#x2764; — ❤ (hex) -->
Пространства имён (namespaces)
Чтобы избежать конфликта одинаковых имён из разных словарей, используют префиксы и xmlns.
<!-- Объявляем namespace с префиксом h, привязанным к URI -->
<root xmlns:h="http://example.com/html"
xmlns:f="http://example.com/furniture">
<h:table> <!-- table из словаря HTML -->
<h:tr><h:td>Ячейка</h:td></h:tr>
</h:table>
<f:table> <!-- table из мебельного словаря — не путается -->
<f:width>120</f:width>
</f:table>
</root>
<!-- xmlns="..." без префикса задаёт namespace по умолчанию для поддерева -->
Правила правильной формы (well-formed)
Документ считается well-formed, если соблюдены базовые синтаксические правила. Иначе парсер откажется его читать.
<!-- 1. Ровно один корневой элемент -->
<!-- 2. Каждый открытый тег закрыт: <a>...</a> или <a/> -->
<!-- 3. Правильная вложенность (без пересечений): -->
<b><i>ок</i></b> <!-- ПРАВИЛЬНО -->
<!-- <b><i>плохо</b></i> ОШИБКА: теги пересекаются -->
<!-- 4. Значения атрибутов в кавычках: id="1" -->
<!-- 5. Учёт регистра: <Tag> закрывается только </Tag> -->
<!-- 6. Спецсимволы < и & в тексте экранируются сущностями -->
Комментарии и инструкции обработки
Комментарии служат для пояснений, инструкции обработки (PI) передают команды приложению, читающему XML.
<!-- Это комментарий. Внутри нельзя писать двойной дефис -- -->
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<!-- ^ инструкция обработки (PI): говорит, какой XSLT применить -->
<?php echo "PI может нести любую команду приложению"; ?>
<!-- Общий вид PI: <?цель данные?> -->
XML против HTML (кратко)
Похожий синтаксис, но разные задачи: HTML описывает отображение страницы, XML — структуру данных.
<!-- XML: теги придумываете вы, важен смысл, правила строгие -->
<note>
<to>Аня</to>
<body>Текст</body> <!-- закрывать обязательно -->
</note>
<!-- HTML: фиксированный набор тегов, парсер прощает ошибки, -->
<!-- допускает незакрытые теги (<br>, <img>), регистр не важен -->
<!-- Вывод: XML — данные и строгость, HTML — вёрстка и снисходительность -->
Практический пример: файл конфигурации
Соберём всё вместе: декларация, корень, вложенность, атрибуты, сущности и комментарии в реальном конфиге.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Конфигурация приложения -->
<configuration>
<!-- Настройки подключения к БД через атрибуты -->
<database host="localhost" port="5432">
<name>app_prod</name>
<user>admin</user>
<!-- В пароле спецсимвол & экранирован как &amp; -->
<password>p@ss &amp; key</password>
</database>
<!-- Список фич: повторяющиеся элементы — это нормально -->
<features>
<feature name="cache" enabled="true"/>
<feature name="logs" enabled="false"/>
</features>
<!-- Произвольный SQL прячем в CDATA, чтобы не экранировать < и & -->
<query>
<![CDATA[ SELECT * FROM users WHERE age > 18 AND active = 1 ]]>
</query>
</configuration>
<!-- Готово: валидный, well-formed XML-конфиг. -->