YML/XML-фид не проходит проверку: как найти и исправить ошибки XML

11 минут чтения 1 просмотр
XML-документ YML-фида с подсвеченной ошибкой и исправленным фрагментом кода

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

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

Ниже — практический порядок диагностики. Он подходит владельцу магазина, маркетологу и разработчику: сначала определяем уровень ошибки, затем находим строку, проверяем контекст выше неё и только после исправления синтаксиса переходим к содержимому товаров.

Проверить YML/XML-фид в ФидСтороже — укажите публичный URL файла, чтобы сервис скачал доступную извне версию, определил формат и показал найденные ошибки и предупреждения в отчёте.

1. Сначала определите: ошибка XML или ошибка данных товара

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

<offer id="123">
    <name>Чайник</name>
</offers>

Сообщение может выглядеть как «opening and ending tag mismatch» и содержать строку с </offers>. Исправление — согласовать имена открывающего и закрывающего тегов.

Логическая ошибка устроена иначе:

<price>-100</price>

Такой фрагмент является корректным XML: элемент открыт, значение прочитано, элемент закрыт. Но отрицательная цена не подходит для товарного предложения. Это важно для порядка работы: XML-валидатор найдёт синтаксис, а правила YML и конкретной площадки проверят смысл данных. Не ищите categoryId и цены, пока документ не разбирается целиком.

2. Незакрытые или неправильно закрытые теги

Частая ошибка возникает при ручной сборке XML строками или условном выводе полей. Генератор открыл name, записал текст, но не добавил закрывающий тег:

<offer id="123">
    <name>Чайник
    <price>2990</price>
</offer>

Исправленный фрагмент:

<offer id="123">
    <name>Чайник</name>
    <price>2990</price>
</offer>

Проверяйте три варианта: закрывающий тег отсутствует, в его имени есть опечатка или элементы закрыты не в том порядке. Регистр тоже важен: <Name> и </name> — разные имена. Если фид формирует приложение, исправляйте генератор или шаблон, а не итоговый файл: ручная правка исчезнет при следующей выгрузке.

Не путайте незакрытый элемент с самозакрывающейся записью. Пустой элемент можно записать как <picture/>, но запись <picture> требует отдельного </picture>. Сравните проблемный товар с соседним корректным offer: повторяющаяся разница часто сразу показывает ветку условия, где генератор пропустил окончание элемента.

3. Спецсимвол & в тексте

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

<name>Кофе & чай</name>

Амперсанд нужно представить сущностью &amp;:

<name>Кофе &amp; чай</name>

Основные предопределённые сущности XML:

  • &amp; — амперсанд;
  • &lt; — знак меньше;
  • &gt; — знак больше;
  • &quot; — двойная кавычка;
  • &apos; — апостроф.

В текстовом содержимом обязательно экранируются & и <. Знак > обычно допустим без экранирования, хотя запись &gt; тоже корректна; отдельные последовательности имеют специальные ограничения. В значениях атрибутов дополнительно учитывайте вид кавычек, которыми ограничено значение. Надёжнее поручить экранирование XML-библиотеке и не обрабатывать уже экранированный текст второй раз.

4. Неправильная вложенность элементов

XML читается как дерево. Если name открыт внутри offer, он должен закрыться раньше родительского offer. Следующий порядок неверен:

<offer>
    <name>Товар
</offer>
    </name>

Правильный вариант сохраняет принцип «последним открыт — первым закрыт»:

<offer>
    <name>Товар</name>
</offer>

Парсер может указать на </offer>, потому что именно там обнаружено противоречие. Однако причина находится строкой выше: открытый name ещё не закрыт. При большой вложенности полезно форматировать копию документа с отступами, но не полагаться только на визуальное выравнивание — окончательный ответ должен дать XML-парсер.

5. Лишний или повреждённый символ в XML

До XML-декларации не должно появляться случайного текста. Если приложение отправило предупреждение, отладочную строку или HTML, клиент получает уже не тот документ:

Warning: Undefined variable...

<?xml version="1.0" encoding="UTF-8"?>

Похожая проблема возникает после закрывающего </yml_catalog>, когда в ответ дописывается служебный вывод. Причиной бывают включённый вывод PHP warning, забытый dump, шаблон страницы ошибки, повреждение при склейке частей или запись логов в поток ответа.

Генератор должен отдавать XML отдельно от диагностических сообщений. Предупреждения направляйте в журнал приложения, а HTTP-ошибку — в корректный статус ответа. Проверяйте не только файл на диске, но и байты, которые реально получает внешний запрос: веб-сервер, прокси или middleware могут изменить ответ после генерации.

Сохраните HTTP-ответ в файл и посмотрите его начало и конец обычным текстовым или шестнадцатеричным просмотрщиком. Это помогает заметить невидимый управляющий байт, HTML перед декларацией и хвост после корня. Не удаляйте подозрительный символ вслепую: сначала найдите компонент, который его добавил, иначе дефект вернётся при следующем запросе.

6. Проблемы с кодировкой

Для современных фидов практичный выбор — UTF-8, явно указанный в декларации:

<?xml version="1.0" encoding="UTF-8"?>

Декларация описывает фактические байты, а не преобразует их. Если приложение записало Windows-1251, но объявило UTF-8, парсер может остановиться на кириллице или показать заменяющие символы. Иногда редактор открывает такой файл «нормально», потому что сам угадывает кодировку, тогда как площадка следует декларации и правилам своего XML-парсера.

Симптомы: испорченные русские буквы, ошибка только на строках с кириллицей, разный результат в двух инструментах. Сохраните скачанный ответ без преобразований, определите кодировку байтов и сравните её с декларацией и HTTP-заголовком Content-Type. Поведение при противоречащих подсказках зависит от клиента, поэтому устраняйте само противоречие: генератор, данные и ответ сервера должны согласованно использовать одну кодировку.

Преобразование лучше выполнять один раз на границе генерации. Если база, шаблон и поток ответа по очереди пытаются «исправить» кодировку, текст легко преобразовать дважды. Добавьте в тестовый товар кириллицу, знак валюты, кавычки и длинное тире: такая контрольная строка обнаруживает проблему раньше реального импорта каталога.

7. CDATA и HTML внутри описания товара

Если HTML записан прямо внутрь элемента, XML-парсер воспринимает теги как настоящие дочерние XML-элементы:

<description>
    <p>Описание товара</p>
</description>

Это не обязательно синтаксическая ошибка: фрагмент имеет правильную вложенность. Но получатель может ожидать в description текст, а не элемент p. CDATA позволяет передать разметку как символьные данные без экранирования каждого углового знака:

<description><![CDATA[
<p>Описание товара</p>
]]></description>

CDATA решает только вопрос XML-синтаксиса. Она не гарантирует, что площадка разрешает HTML, конкретные теги или такой способ передачи описания. Сверяйтесь с форматом получателя. Также учитывайте, что последовательность ]]> нельзя помещать внутрь одной секции CDATA без разделения или другой обработки.

8. Дублирующиеся XML-атрибуты

У одного элемента не может быть двух атрибутов с одинаковым именем. Такой открывающий тег не является корректным XML:

<offer id="123" id="456">

Оставьте одно значение:

<offer id="123">

Дублирование часто появляется, когда базовый шаблон уже записал id, а дополнительный модуль добавил его повторно. Не выбирайте одно значение случайно: определите, какой идентификатор стабильно связан с товаром. После исправления проверьте уникальность offer id во всём фиде — это уже логическая проверка YML, отдельная от запрета одинаковых атрибутов внутри одного элемента.

9. Несколько корневых элементов

XML-документ должен иметь ровно один корневой элемент. Две последовательные выгрузки нельзя просто склеить:

<yml_catalog>
    ...
</yml_catalog>

<yml_catalog>
    ...
</yml_catalog>

Общая форма YML выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="...">
    <shop>
        ...
    </shop>
</yml_catalog>

Все разделы относятся к этому дереву. Если нужна схема блоков shop, currencies, categories и offers, откройте отдельное руководство «YML-фид: что это такое, как создать и проверить». Здесь достаточно убедиться, что генератор создаёт один документ, а не дописывает новую выгрузку в конец старой.

10. Неожиданный конец файла или оборванный XML

Если скачивание или генерация завершились раньше времени, документ заканчивается внутри открытых элементов:

<offers>
    <offer id="123">
        ...

Парсер сообщает о неожиданном конце, хотя начало файла выглядит нормально. Возможные причины: авария генератора, лимит памяти, timeout, исчерпание места, разрыв передачи или публикация файла в момент его перезаписи. Сравните текущий размер и число предложений с обычными значениями, повторите скачивание и проверьте последние строки.

Если обрыв плавает или связан с HTTP-ответом, используйте инструкцию о статусах 403, 404, 500, редиректах и таймаутах YML-фида. Исправлять закрывающие теги вручную бессмысленно: потерянные товары не восстановятся, а следующая генерация снова создаст повреждённый файл.

Безопасная публикация строится в два этапа: сначала генератор пишет временный файл и проверяет его, затем готовая версия заменяет публичную одним файловым действием. Тогда внешний клиент не скачает документ в середине записи. Дополнительно контролируйте размер, число offer и наличие закрывающего корневого тега до замены.

11. Как найти место ошибки в большом YML-фиде

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

  1. Скачайте ту же версию фида, которую проверяет площадка, и сохраните её без редактирования.
  2. Получите полный текст ошибки XML-парсера.
  3. Запишите номер строки и позицию, если инструмент их сообщает.
  4. Откройте указанную строку и несколько строк до неё.
  5. Проверьте совпадение тегов и найдите последний открытый, но не закрытый элемент.
  6. Проверьте необработанные амперсанды, угловые скобки и кавычки в атрибутах.
  7. После правки заново запустите полную проверку всего документа.

Локально можно использовать любой строгий XML-парсер; например, при наличии xmllint команда xmllint --noout feed.xml вернёт диагностическое сообщение без преобразования файла. В редакторе отключите автоматическую смену кодировки и переносы, которые меняют номера строк.

Если файл генерируется без переводов строк и весь документ занимает одну строку, ориентируйтесь на номер позиции и ближайший фрагмент. Для расследования можно создать отдельную форматированную копию, но не загружайте её вместо исходника: форматирование меняет координаты и иногда маскирует проблему с кодировкой. После нахождения товара сопоставьте его offer id с источником данных и проверьте соседние поля, из которых генератор собрал повреждённый текст.

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

12. Почему XML открывается в браузере, но всё равно остаётся проблемным

Открытая страница доказывает только доступность URL для вашего браузера и получение какого-то ответа. Если браузер показывает структурированное дерево без сообщения парсера, это полезный признак синтаксической целостности, но не полная проверка фида.

Разделяйте пять уровней: URL доступен; ответ скачан полностью; XML синтаксически корректен; структура соответствует YML; данные удовлетворяют правилам конкретной площадки. Например, <price>-100</price> откроется как XML, но останется неправильной ценой. Так же браузер не подтвердит обязательность полей, допустимость HTML в описании или доступность URL роботу с другого IP.

После исправления XML запустите общую проверку по статье «Как проверить YML-фид и исправить ошибки». Она помогает перейти от синтаксиса к категориям, идентификаторам, ценам, ссылкам и качеству товарных данных.

13. Чеклист проверки XML-фида

  • Файл скачивается полностью, а его размер не выглядит неожиданно маленьким.
  • XML содержит один корневой элемент.
  • Все открытые теги закрыты теми же именами и в правильном порядке.
  • Вложенность элементов не нарушена.
  • Амперсанды и другие служебные символы корректно обработаны.
  • До декларации и после корня нет предупреждений, HTML или отладочного вывода.
  • Фактическая кодировка соответствует XML-декларации.
  • В одном элементе нет атрибутов с одинаковыми именами.
  • Документ не обрывается внутри offer, offers или другого блока.
  • После исправления XML отдельно проверены структура YML и данные товаров.

Исправили XML — проверьте следующий уровень

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

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

Проверьте YML/XML-фид в ФидСтороже — сервис скачает файл по публичному URL, проанализирует его формат и структуру и покажет найденные проблемы в отчёте. Это помогает отделить ошибку парсинга XML от следующих замечаний к фиду.

 Вернуться в блог

Оформление подписки недоступно

В данный момент оформить подписку нельзя. Попробуйте позже.