Ошибка «неопределённая сущность» (undefined entity) возникает, когда XML-парсер встречает в документе конструкцию вида , © или « и не находит её объявления — в XML, в отличие от HTML, предопределены только пять сущностей: &, <, >, " и '. Всё остальное парсер обязан считать ошибкой, и обработка документа останавливается.
Чаще всего с этой проблемой сталкиваются при открытии XML-файлов в браузере, при загрузке фидов (RSS, YML для маркетплейсов), при чтении конфигурационных файлов и при обмене данными между системами. Типичный источник — текст, скопированный из HTML-страницы или выгруженный из CMS, где HTML-сущности разрешены. Ниже разберём, как найти проблемное место и исправить документ без потери данных.
Почему XML не понимает HTML-сущности
Спецификация XML жёстко ограничивает набор встроенных сущностей пятью штуками, перечисленными выше. Любая другая конструкция вида &имя; должна быть либо объявлена в DTD-документе, либо заменена числовой ссылкой на символ. Парсер не «догадывается», что — это неразрывный пробел: для него это просто неизвестное имя.
В HTML ситуация иная: там определены сотни именованных сущностей, и браузер спокойно обрабатывает , —, ™ и подобные. Поэтому контент, безупречно работающий на веб-странице, ломается при экспорте в XML. Это самая частая причина ошибки — смешение правил двух разных языков разметки.
- 📄 Текст скопирован из HTML-страницы или визуального редактора CMS;
- 🔄 Автоматическая выгрузка, где генератор подставляет HTML-сущности;
- 🧩 Ручное редактирование XML с добавлением «привычных» entity;
- 📦 Сторонний фид от поставщика, сформированный без учёта спецификации XML.
Как выглядит ошибка в разных инструментах
Формулировка сообщения зависит от парсера, но суть одна. Браузеры на базе Chromium показывают страницу ошибки с текстом вроде «Entity 'nbsp' not defined» и указанием строки и колонки. Firefox выводит «XML Parsing Error: undefined entity» с адресом файла и позицией.
В библиотеках языков программирования сообщения похожи: lxml для Python сообщает Entity 'nbsp' not defined, а встроенный модуль xml.etree.ElementTree выдаёт ParseError: undefined entity с координатами. Номера строки и колонки — первое, на что стоит смотреть: они указывают точное место сбоя.
| Среда | Типичный текст ошибки |
|---|---|
| Браузер (Chromium) | error on line N: Entity 'nbsp' not defined |
| Firefox | XML Parsing Error: undefined entity, Line Number N, Column M |
| Python (ElementTree) | ParseError: undefined entity: line N, column M |
| PHP (DOM/SimpleXML) | Entity 'nbsp' not defined in Entity |
Шаг 1. Найдите проблемную сущность
Откройте XML-файл в текстовом редакторе с нумерацией строк — подойдут Notepad++, VS Code или любой аналог. Перейдите к строке и колонке из сообщения об ошибке: там вы увидите конструкцию вида &что-то;, которую парсер не смог распознать.
Если файл большой, удобнее воспользоваться поиском по регулярному выражению. В большинстве редакторов включите режим regex и найдите все сущности разом:
&[a-zA-Z]+;
Так вы получите полный список сущностей в документе и сможете сразу отделить разрешённые пять от проблемных. Исправлять нужно все нестандартные сущности сразу — парсер останавливается на первой, но за ней почти всегда следуют другие.
Шаг 2. Замените сущности корректными конструкциями
Самый надёжный способ — заменить именованную сущность на числовую ссылку на символ (numeric character reference). Числовые ссылки вида   или   валидны в любом XML-документе и не требуют объявлений. Например, неразрывный пробел записывается как  , а длинное тире — как —.
Альтернатива — вставить сам символ Unicode напрямую в текст, если файл сохранён в кодировке UTF-8. Вместо « просто напишите «ёлочку» обычным символом. Это делает документ читабельнее, но требует аккуратности с кодировкой: файл обязательно должен быть сохранён в UTF-8 без BOM-конфликтов.
- 🔢
→ (неразрывный пробел); - ➖
—→—(длинное тире); - ©️
©→©(знак копирайта); - 💬
«/»→«/».
Шаг 3. Проверьте амперсанды и CDATA-секции
Отдельный частый сценарий — «голый» амперсанд в тексте, например в URL с параметрами: ?a=1&b=2. В XML символ & обязан экранироваться как &, иначе парсер воспринимает следующее слово как имя сущности и выдаёт ту же ошибку undefined entity. Проверьте все URL и текстовые значения на неэкранированные амперсанды.
Если в XML нужно вставить фрагмент HTML или текст с большим количеством спецсимволов, оберните его в секцию CDATA. Внутри <![CDATA[ ... ]]> парсер не интерпретирует разметку и сущности — всё передаётся как есть.
<description><![CDATA[Цена: 100 & 200 <руб.>]]></description>
⚠️ Внимание: CDATA не делает недопустимые символы допустимыми на уровне приложения. Если принимающая система сама парсит содержимое как HTML, лишние сущности внутри CDATA могут вызвать проблемы уже на её стороне. Проверяйте требования конкретного приёмника данных.
☑️ Проверка XML перед отправкой
Шаг 4. Исправьте генерацию, а не только файл
Ручная правка решает проблему один раз, но если XML формируется скриптом или CMS, ошибка вернётся при следующей выгрузке. Найдите место в коде, где текст подставляется в XML, и убедитесь, что используется корректное экранирование. В Python для этого служит xml.sax.saxutils.escape(), в PHP — htmlspecialchars() с подходящими флагами либо штатные средства DOMDocument.
Если фид приходит от стороннего поставщика и править генератор невозможно, вариантов два: попросить поставщика исправить выгрузку (это нарушение спецификации XML с его стороны) или предобрабатывать файл перед парсингом — заменять известные HTML-сущности на числовые ссылки. Второй путь рабочий, но поддерживать список замен придётся самостоятельно.
⚠️ Внимание: не отключайте строгий режим парсера и не используйте «заглушки» вроде подмены парсера на HTML-обработчик для производственных данных. Это маскирует ошибку и может привести к тихому искажению содержимого документа.
Как объявить собственные сущности через DTD
Технически сущность можно объявить в начале документа: <!DOCTYPE root [<!ENTITY nbsp " ">]>. После этого станет валидной. Однако внешние DTD многие парсеры не загружают из соображений безопасности (защита от XXE-атак), поэтому приём системами вроде маркетплейсов не гарантирован. Предпочтительнее числовые ссылки.
Проверка результата
После правок откройте файл в браузере: если документ отображается как дерево элементов без красной страницы ошибки — синтаксис корректен. Для автоматической проверки удобна команда xmllint, доступная в Linux и macOS:
xmllint --noout file.xml
Отсутствие вывода означает, что документ well-formed. Если парсер снова сообщает об ошибке, смотрите на новые координаты — вероятно, осталась ещё одна сущность, которую вы пропустили при первом проходе.
Частые вопросы
Почему работает в HTML, но ломает XML?
В HTML определены сотни именованных сущностей, а в XML — только пять: amp, lt, gt, quot, apos. Всё остальное требует объявления в DTD или замены числовой ссылкой вида  .
Можно ли просто удалить проблемные сущности?
Можно, но с осторожностью: сущность обычно обозначает осмысленный символ (неразрывный пробел, тире, кавычку). Удаление изменит текст. Корректнее заменить её числовой ссылкой или самим символом Unicode.
Ошибка указывает на строку, но там нет никакой сущности. Что делать?
Проверьте предыдущие строки: иногда сбой происходит из-за незакрытого тега или неэкранированного амперсанда выше, а парсер «спотыкается» позже. Также убедитесь, что смотрите тот же файл, который реально открывается приложением.
Как массово исправить сущности в большом файле?
Используйте поиск с заменой по регулярному выражению в редакторе или небольшой скрипт: найдите все вхождения &[a-z]+; и замените известные имена на числовые ссылки по заранее составленному словарю соответствий.
Поможет ли смена кодировки файла?
Нет, ошибка undefined entity не связана с кодировкой. Кодировка влияет на отображение символов, а сущность — это конструкция разметки, которую парсер должен распознать независимо от того, в UTF-8 файл или в другой кодировке.