# Загрузка через XML/YML

Базовый формат товарной выгрузки REES46 основан на YML (Yandex Market Language), более подробное описание которого доступно в разделе помощи Яндекс по ссылке (opens new window).

# Поддерживаемые кодировки

  • UTF-8
  • Windows-1251 (не рекомендуется с 2010 года)

# Основные элементы

Элемент Обязательность Описание
xml обязательно Стандартный XML-заголовок. Должен начинаться с первой строки и нулевого символа в строке.
yml_catalog обязательно Корневой элемент XML-документа товарной выгрузки.
shop обязательно Основной элемент товарной выгрузки, содержащий описание магазина и товаров.

# Элемент xml

Доступные атрибуты:

Атрибут Обязательность Описание
version обязательно Версия языка XML-документа. Необходимо использовать версию "1.0".
encoding обязательно Кодировка, используемая в XML-документе (из доступных).

Пример:

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

# Элемент yml_catalog

Доступные атрибуты:

Атрибут Обязательность Описание
date обязательно Дата создания (генерации) XML-документа в формате YYYY-MM-DD hh:mm.

Пример:

<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2019-05-16 17:19">
...
</yml_catalog>

# Элемент yml_catalog > shop

Дочерние элементы shop:

Элемент Обязательность Описание
name обязательно Краткое название магазина.
company обязательно Наименование компании, владеющей магазином.
url обязательно Ссылка на главную страницу магазина.
currencies обязательно Список курсов валют магазина.
categories обязательно Список категорий магазина.
locations не обязательно Список локаций, в которых представлен магазин.
offers обязательно Список товаров магазина.

# Базовые элементы yml_catalog > shop > *

Пример:

<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2019-05-16 17:19">
    <shop>
        <name>Мой магазин</name>
        <company>Компания моего магазина</company>
        <url>https://my-store.com</url>
    ...
    </shop>
</yml_catalog>

# Элемент yml_catalog > shop > currencies

Элемент currencies задает список курсов валют магазина. Каждая из валют описывается отдельным элементом currency.

Доступные атрибуты элемента currency:

Атрибут Обязательность Описание
id обязательно Код валюты.
rate обязательно Курс валюты по отношению к основной валюте. Значение данного атрибута для основной валюты должно быть равно 1 (rate="1"). В качестве десятичного разделителя может использоваться только символ точки.

Пример:

<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2019-05-16 17:19">
    <shop>
        <name>Мой магазин</name>
        <company>Компания моего магазина</company>
        <url>https://my-store.com</url>
        
        <currencies>
            <currency id="RUR" rate="1"/>
            <currency id="USD" rate="64.45"/>
            <currency id="EUR" rate="72.03"/>
            ...
        </currencies>
    ...
    </shop>
</yml_catalog>

# Элемент yml_catalog > shop > categories

Элемент categories содержит список категорий магазина. Каждая категория описывается отдельным элементом category.

Доступные атрибуты элементы category:

Атрибут Обязательность Описание
id обязательно Идентификатор категории.
parentId не обязательно Идентификатор родительской категории.
url не обязательно Ссылка на страницу категории.
alias не обязательно Словесный идентификатор категории.

Пример:

<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2019-05-16 17:19">
    <shop>
        <name>Мой магазин</name>
        <company>Компания моего магазина</company>
        <url>https://my-store.com</url>
        
        <currencies>
            <currency id="RUR" rate="1"/>
            <currency id="USD" rate="64.45"/>
            <currency id="EUR" rate="72.03"/>
            ...
        </currencies>
        
        <categories>
            <category id="2" url="http://my-store.com/categories/discount/">Распродажа</category>
            <category id="8" url="http://my-store.com/categories/men/">Мужчинам</category>
            <category id="13" parentId="8" url="http://my-store.com/categories/men/shoes/">Shoes</category>
            <category id="97" parentId="13" alias="men/shoes/leather" url="http://my-store.com/categories/men/shoes/leather">Leather Shoes</category>
            ...
        </categories>
    ...
    </shop>
</yml_catalog>

# Элемент yml_catalog > shop > locations

Элемент locations содержит список локаций магазина. Каждая локация описывается отдельным элементом location.

Доступные атрибуты элементы location:

Атрибут Обязательность Описание
id обязательно Идентификатор локации.
name обязательно Название локации.
parentId не обязательно Идентификатор родительской локации.
type не обязательно Тип локации. Доступные значения: state, city, store.
group не обязательно Признак группировки нескольких локаций в определенную группу. Любое строковое значение. Пример: ХолодныеРегионы.
search_level_up не обязательно Атрибут определяет возможность расширения поиска вверх по иерархии родительских локаций. Если значение равно 0, поиск не пойдёт выше. Если значение больше ноля, повторный поиск производится в родительских локациях, но будет ограничен существующей иерархией.

Иерархия локаций

search_level_up работает только с иерархией локаций, заданной в товарном фиде при помощи атрибута parentId. Корректное выстраивание иерархии является ответственностью товарного фида. Если цепочка parentId задана некорректно или обрывается, расширение поиска не выполняется.

То есть, если товар отсутствует в конкретной торговой точке, поиск не будет автоматически выполняться по всему городу или региону без явно заданной иерархии.

Пример:

<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2019-05-16 17:19">
    <shop>
        <name>Мой магазин</name>
        <company>Компания моего магазина</company>
        <url>https://my-store.com</url>
        
        <currencies>
            <currency id="RUR" rate="1"/>
            <currency id="USD" rate="64.45"/>
            <currency id="EUR" rate="72.03"/>
            ...
        </currencies>
        
        <categories>
            <category id="2" url="http://my-store.com/categories/discount/">Распродажа</category>
            <category id="8" url="http://my-store.com/categories/men/">Мужчинам</category>
            <category id="13" parentId="8" url="http://my-store.com/categories/men/shoes/">Shoes</category>
            <category id="97" parentId="13" alias="men/shoes/leather" url="http://my-store.com/categories/men/shoes/leather">Leather Shoes</category>
            ...
        </categories>
        
        <locations>
            <location id="1" type="city" name="Москва" group="ДенежныеГорода" />
            <location id="2" type="city" name="Санкт-Петербург" group="ДенежныеГорода" />
            <location id="145" parentId="1" type="store" name="Пункт выдачи на Арбате" search_level_up="1" />
            ...
        </locations>
    ...
    </shop>
</yml_catalog>

# Элемент yml_catalog > shop > offers

Элемент offers содержит список товаров магазина. Каждый товар описывается отдельным элементом offer.

Обратите внимание

Элемент offer не может содержать вариант товара, а только сам товар. Если в вашем магазине все варианты одного товара находятся на одной странице сайта и нет общего идентификатора для вариантов товара, то вам необходимо использовать какой-то один из вариантов в качестве основного - его идентификатор, цену и пр. данные. Обычно выбирают самый дешёвый вариант товара в качестве основного, а флаг наличия в данном случае должен вписаться в следующую логику – если хотя бы один вариант товара есть в наличии, то товар должен считаться в наличии.

# Элемент yml_catalog > shop > offers > offer

Доступные атрибуты элемента offer:

Атрибут Обязательность Описание
id обязательно Идентификатор товара.
group_id обязательно Идентификатор группы товаров. Необходим для объединения вариантов товаров в одну группу. В ответе блоков рекомендаций и поиска будет возвращен только один из вариантов.
available обязательно Флаг наличия товара. Доступные значения: true, false.
ignored не обязательно Флаг учета товара. Если передан false, товар не будет выводиться в результатах работы инструментов. Доступные значения: true, false.
leftovers не обязательно Остаток товара. Может принимать одно из значений: one (товар доступен в единственном экземпляре), few (товар в ограниченном количестве (до 10 ед.)), lot (доступно от 10 и более единиц товара).

Лайфхак

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

Дочерние элементы offer:

Элемент Обязательность Описание
name обязательно Полное название товара. Для раздельного написания названия см. элементы: typePrefix, vendor, model.
picture обязательно Ссылка на изображение товара.
price обязательно Базовая цена товара.
price_with_promocode обязательно Базовая цена товара с учетом использования промокода.
url обязательно Ссылка на страницу товара.
categoryId обязательно Категория товара. Этих элементов может быть несколько.
deeplink_android не обязательно Ссылка на страницу товара в приложении (Android).
deeplink_ios не обязательно Ссылка на страницу товара в приложении (Ios).
locations не обязательно Элемент, описывающий свойства товара в разных локациях: наличие, цена. См. таблицу и пример ниже.
accessories не обязательно Элемент, описывающий список аксессуаров текущего товара. См. пример ниже.
oldprice не обязательно Старая цена товара.
discount_percent не обязательно Процент скидки. При отсутствии в импорте данного параметра и наличии oldprice, он будет автоматически рассчитан по формуле: целая часть от ((oldprice - price) / oldprice) * 100 (получается путём округления вниз до целого)
price_margin не обязательно Относительная маржинальность (приоритет) товара (от 0 до 100).
barcode не обязательно Штрих-код товара.
typePrefix не обязательно Тип/категория товара (например, "мобильный телефон", "стиральная машина", "угловой диван").
vendor не обязательно Производитель/бренд.
vendorCode не обязательно Код производителя для данного товара.
model не обязательно Модель и название товара.
seasonality не обязательно Сезонность товара. В качестве значения используется порядковый номер месяца ( от 1 до 12). Этих элементов может быть несколько.
is_new не обязательно Может принимать только одно значение - "1", означающее, что товар является новинкой.
rating не обязательно Рейтинг товара. Целочисленное значение от 1 до 5.
description не обязательно Описание товара.
stock_quantity не обязательно Количество товара. Целочисленное значение от 1 и более.
tags не обязательно Элемент, описывающий связанные с товаром теги, для точного поиска. См. таблицу и пример ниже.
merchant не обязательно ID продавца. (Актуально для маркетплейсов)
param не обязательно Параметр.
date не обязательно Дата добавления или обновления.
gift не обязательно Информация о подарке.
installment не обязательно Информация о рассрочке.
promocode не обязательно Промокод.
bonuses_accrual_allowed не обязательно Управление возможностью начисления бонусов за товар. Значения: true или false
bonuses_spending_allowed не обязательно Управление возможностью списания бонусов за товар. Значения: true или false
discounts_allowed не обязательно Управление возможностью применения скидок к товару. Значения: true или false

Примите во внимание

При обработке url к ссылке добавляются параметры вида recommended_by, recommended_code и т.д. Они необходимы для работы трекинга событий и построения аналитики.

Если вам нужно передать в ссылке собственные параметры, их требуется закодировать. В противном случае некоторые символы будут некорректно обработаны, например, согласно спецификации RFC3986 знак + распознается как пробел. Если вам нужно, чтобы при переходе по ссылке в параметре передавался знак +, то его нужно экранировать в %2B.

Пример:

http://test.com?test=+-!ABC -> http://test.com?test=%2B-%21ABC

Сезонность

Если у товара указана сезонность, и она совпадает с текущим месяцем, он получает буст 1.2.

Если сезонность — следующий месяц, буст будет 1.1.

Если указаны оба месяца (текущий и следующий), коэффициенты умножаются. Например: сезонность — июнь и июль, сейчас июнь → буст: 1.2 × 1.1 = 1.32.

Если сезонность не указана — считается универсальным товаром, буст тоже 1.2.

Во всех других случаях — буст 1.0.

# Элемент yml_catalog > shop > offers > offer > locations

Элемент locations содержит список локаций, а также доступность и цену текущего товара в локациях. Каждая локация описывается отдельным элементом location.

Атрибуты элемента location:

Атрибут Обязательность Описание
id обязательно Идентификатор, соответствующий локации (идентификатору) из элемента locations элемента shop. Подробнее об описании локации см. в соответствующем подразделе этого документа и в примере ниже.
weight не обязательно Приоритет товара в локации (от 0 до 100).

Обратите внимание

Товар будет считаться доступным к приобретению только в перечисленных в элементе offer локациях. Во всех остальных известных, но не перечисленных локациях, товар будет считаться не в наличии. Если же у offer отсутствует элемент locations, то товар считается в наличии во всех локациях магазина.

Дочерние элементы:

Элемент Обязательность Описание
price не обязательно Цена товара в локации. Если элемент отсутствует, то используется базовая цена товара.
oldprice не обязательно Старая цена товара в локации. Если элемент отсутствует, то используется базовая старая цена товара (при наличии).
stock_quantity не обязательно Количество товара. Целочисленное значение от 1 и более.

# Элемент yml_catalog > shop > offers > offer > tags

Элемент tags содержит список тегов, соотносящихся с товаром. Каждое значение описывается отдельным элементом tag.

Элемент Обязательность Описание
tag обязательно Значение тега.

# Пример полного XML-файла

<?xml version="1.0" encoding="UTF-8"?>
<yml_catalog date="2019-05-16 17:19">
    <shop>
        <name>Мой магазин</name>
        <company>Компания моего магазина</company>
        <url>https://my-store.com</url>
        <!-- перечисление валют магазин и курсов валют -->
        <currencies>
            <currency id="RUR" rate="1"/>
            <currency id="USD" rate="64.45"/>
            <currency id="EUR" rate="72.03"/>
        </currencies>
        <!-- перечисление всех категорий магазина, их иерархии и ссылок -->
        <categories>
            <category id="2" url="http://my-store.com/categories/apple/">Apple</category>
            <category id="13" parentId="2" alias="apple/phones" url="http://my-store.com/categories/apple/phones/">Телефоны</category>
        </categories>
        <!-- перечисление всех локаций магазина -->
        <locations>
            <location id="1" type="city" name="Москва" />
            <location id="2" type="city" name="Санкт-Петербург" />
            <location id="3" type="city" name="Новосибирск" />
        </locations>
        <offers>
            <offer id="395532" available="true" leftovers="few">
                <url>http://my-store.com/items/395532</url>
                <deeplink_android>http://my-store.com/items/395532</deeplink_android>
                <deeplink_ios>http://my-store.com/items/395532</deeplink_ios>
                <price>50000</price>
                <price_with_promocode>40000</priceWithPromocode>
                <oldprice>55000</oldprice>
                <price_margin>67</price_margin>
                <!-- перечисление иерархий категорий, в которых присутствует данный товар -->
                <categoryId>2</categoryId>
                <categoryId>13</categoryId>
                <!-- Указана сезонность. Приоритетные месяцы для данного товара: январь, март, апрель, июнь. -->
                <seasonality>1</seasonality>
                <seasonality>3</seasonality>
                <seasonality>4</seasonality>
                <seasonality>6</seasonality>
                <!-- перечисление локаций, в которых данный товар доступен к приобретению, а также уточнение цены товара в локации -->
                <locations>
                    <location id="1" weight="80">
                        <price>70000</price>
                        <oldprice>75000</oldprice>
                        <stock_quantity>10</stock_quantity>
                    </location>
                    <!-- локация id="2" не указана, значит товар в этой локации отсутствует -->
                    <!-- в локации id="3" не указан price, значит цена товара соответствует базовой -->
                    <location id="3"></location>
                </location>
                <!-- Перечислены ID товаров, являющиеся аксессуарами для текущего товара -->
                <accessories>
                    <accessory id="5574" />
                    <accessory id="131" />
                    <accessory id="99444" />
                    <accessory id="334411" />
                </accessories>
                <tags>
                    <tag>телефон</tag>
                    <tag>смартфон</tag>
                </tags>
                <barcode>123456</barcode>
                <picture>https://my-store.com/items/395532.jpg</picture>
                <name>Apple Iphone 6 128 gb</name>
                <typePrefix>Смартфон</typePrefix>
                <vendor picture="http://example.com/apple.jpg">Apple</vendor>
                <vendorCode>APPL</vendorCode>
                <model>iPhone 6 128Gb</model>
                <is_new>1</is_new>
                <rating>5</rating>
                <date>2022-01-01</date>
                <description><![CDATA[iPhone 6 не просто больше. Он лучше во всех отношениях. 4,7-дюймовый HD-дисплей Retina. Процессор A8 с 64-разрядной архитектурой уровня настольного компьютера. Новая 8-мегапиксельная камера iSight с технологией Focus Pixels. Сенсор идентификации по отпечатку пальца Touch ID. Скорость Wi-Fi выше. Время работы от аккумулятора дольше. А также iOS 8 и iCloud. Все это - в цельном корпусе толщиной всего 6,9 мм.]]></description>
                <merchant>abc123xyz789</merchant>
                <param name="Color">Black</param>
                <!-- Параметр unit указывает на то, что значение параметра числовое и для него можно использовать range фильтрацию -->
                <param name="Heigth" unit="mm">140</param>
                <!-- Параметр priority позволяет передавать значение для произвольной сортировки параметров в ответе полного поиска -->
                <param name="Sim" priority="20">E-sim</param>
                <installment>36</installment> 
                <discount_percent>50</discountPercent> 
                <promocode>Discount20</promocode> 
                <gift>true</gift> 
                <bonuses_accrual_allowed>true</bonuses_accrual_allowed>
                <bonuses_spending_allowed>true</bonuses_spending_allowed>
                <discounts_allowed>true</discounts_allowed>
            </offer>
            <offer id="395533" available="false">
                ...
            </offer>
            ...
        </offers>
    </shop>
</yml_catalog>

# Нишевые параметры

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

# Рекомендации по генерации товарного фида

# Генерация файла по расписанию

Если XML вашего магазина имеет размер больше 5 мегабайт и режиме реального времени создаётся дольше 20 секунд, будет лучше, если вместо того, чтобы указывать ссылку на скрипт генерации XML, вы поставите задачу генерации XML в расписание. Ваш скрипт должен генерировать статичный XML-файл, скачивание которого начнется сразу при обращении к нему, без затрат времени на генерацию. Это даст вам следующие преимущества:

  • снижение нагрузки на ваш сервер при больших XML (иначе будет очень легко устроить вам DDOS-атаку, сделав 20-30 одновременных запросов к этому ресурсоемкому скрипту);
  • ускорение загрузки вашего YML нашими серверами – вместо того, чтобы ждать генерации файла по 10-15 минут, REES46 сразу начнет их выкачивать и это повысит актуальность вашей товарной базы платформе.

Пример такого расписания для cron:

0 */2 * * * php /home/myuser/site/docs/xml.php > /home/myuser/site/docs/rees46.xml

Обратите внимание

Если генерация файла занимает больше нескольких секунд, рекомендуем сохранять временный файл отдельно, а потом, когда генерация будет закончена, подменить им тот файл, который доступен снаружи. Иначе может возникнуть ситуация, что файл будет заменен частично в процессе выкачивания его платформой и в платформу попадет неполный файл и обработка закончится с ошибкой.

# Архивы

Для того, чтобы ускорить выкачивание больших XML-файлов, вы можете архивировать их архиватором GZIP. Сервис автоматически определяет архивированный файл, распаковывает его и обрабатывает. Формат архива – GNU Gzip (opens new window).

# Использование Database Mirroring

  1. Нужно добавить новый режим синхронизации данных о товарах - промежуточная база данных
  2. При переключении в новый режим создаётся новая база с новым пользователем
  3. Данные для доступа - shop_id:shop_secret. Путь к базе выводится на странице настроек магазина
  4. Список таблиц - categories, locations, products
  5. Структура:
  • categories

    • category_id - varchar(255)
    • parent_id - varchar(255)
    • active - boolean
    • name - varchar(255)
    • url - varchar(255)
    • updated_at - timestamp(6) = now()
    • processed_at - timestamp(6)
  • locations

    • location_id - varchar(255)
    • active - boolean
    • name - varchar(255)
    • updated_at - timestamp(6) = now()
    • processed_at - timestamp(6)
  • products

    • product_id - varchar(255)
    • active - boolean
    • data - jsonb(65,535)
    • updated_at - timestamp(6) = now()
    • processed_at - timestamp(6)

Колонка active предназначена для обновления сведений о наличии данных, без их удаления.

При каждой обработке система забирает данные а затем фильтрует их по колонкам: updated_at, active.

Они передаются в API порциями по 2000 штук. Время в колонке processed_at обновляется.

Обратите внимание

При каждом обновлении обязательно проставлять текущее время (UTC=0) в колонке updated_at

# Правила работы с таблицами

  1. Данные могут записываться в любой последовательности
  2. Строки в таблице можно удалять, либо переключать значение колонки active на false. Такие строки будут игнорироваться

Обратите внимание

При обновлении строки нужно обновить значение колонки updated_at на текущий timestamp и НЕ ОБНОВЛЯТЬ колонку processed_at. Если данные в строке не обновлялись, обновлять значение колонки updated_at НЕЛЬЗЯ.