Parsing YML feeds for importing products into 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Parsing YML Feeds for Product Import to 1C-Bitrix

YML (Yandex Market Language) is an XML format developed by Yandex.Market for product feeds. Suppliers often provide YML: the format is documented, structure is known, data is complete. It's simpler than parsing arbitrary Excel, but has its own nuances.

YML Feed Structure

YML feed has a standard structure:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE yml_catalog SYSTEM "shops.dtd">
<yml_catalog date="2024-01-15 10:30">
  <shop>
    <name>Store Name</name>
    <currencies>
      <currency id="RUR" rate="1"/>
    </currencies>
    <categories>
      <category id="1">Electronics</category>
      <category id="2" parentId="1">Smartphones</category>
    </categories>
    <offers>
      <offer id="12345" available="true">
        <url>https://shop.ru/product/12345</url>
        <price>29990</price>
        <currencyId>RUR</currencyId>
        <categoryId>2</categoryId>
        <picture>https://shop.ru/img/12345.jpg</picture>
        <name>Samsung Galaxy A54 Smartphone</name>
        <vendor>Samsung</vendor>
        <vendorCode>SM-A546</vendorCode>
        <description>Product description</description>
        <param name="Color">Black</param>
        <param name="Memory">128 GB</param>
      </offer>
    </offers>
  </shop>
</yml_catalog>

Key elements:

  • offer id — unique product identifier from supplier (like XML_ID in Bitrix).
  • available — availability: true/false.
  • categoryId — reference to category.
  • param — product characteristics (any number).

Parsing Categories and Building Tree

Categories in YML form a hierarchy through parentId attribute. On import, create corresponding section structure in Bitrix infoblock.

Algorithm:

  1. Load all categories into associative array [id => ['name' => ..., 'parentId' => ...]].
  2. Recursively build tree.
  3. For each category: find section by XML_ID = 'yml_cat_{id}' or create new.
  4. Save mapping [yml_id => bitrix_section_id].
$sectionId = CIBlockSection::GetList(
    [],
    ['IBLOCK_ID' => $iblockId, 'XML_ID' => 'yml_cat_' . $cat['id']],
    false,
    ['ID']
)->Fetch()['ID'];

if (!$sectionId) {
    $bs = new CIBlockSection();
    $sectionId = $bs->Add([
        'IBLOCK_ID' => $iblockId,
        'XML_ID'    => 'yml_cat_' . $cat['id'],
        'NAME'      => $cat['name'],
        'IBLOCK_SECTION_ID' => $parentBitrixId,
        'ACTIVE'    => 'Y',
    ]);
}

Importing Products (Offers)

Main processing loop:

foreach ($xml->shop->offers->offer as $offer) {
    $xmlId = (string)$offer['id'];
    $available = (string)$offer['available'] === 'true';

    // Collect parameters
    $params = [];
    foreach ($offer->param as $param) {
        $params[(string)$param['name']] = (string)$param;
    }

    $fields = [
        'IBLOCK_ID'         => $iblockId,
        'NAME'              => (string)$offer->name,
        'XML_ID'            => $xmlId,
        'ACTIVE'            => $available ? 'Y' : 'N',
        'IBLOCK_SECTION_ID' => $sectionMap[(string)$offer->categoryId] ?? null,
        'PROPERTY_VALUES'   => [
            'VENDOR'  => (string)$offer->vendor,
            'ARTICLE' => (string)$offer->vendorCode,
            // characteristics from param
        ],
    ];

    // Find existing product
    $existId = getElementByXmlId($xmlId, $iblockId);

    $el = new CIBlockElement();
    if ($existId) {
        $el->Update($existId, $fields);
    } else {
        $el->Add($fields);
    }

    // Update price
    updatePrice($existId ?: $el->LAST_ID, (float)$offer->price);
}

Image Download

YML contains image links (<picture>). Download and attach to product:

$imageUrl = (string)$offer->picture;
$tmpFile = CFile::MakeFileArray($imageUrl); // Bitrix will download the file
if ($tmpFile) {
    $el->Update($productId, ['PREVIEW_PICTURE' => $tmpFile]);
}

Image download is the slowest part of import. For 10,000-item feed — downloading 10,000 images. Optimization: check if image changed (by URL hash or content), don't download again.

YML Offer Types

YML supports several offer types with different required fields:

Type Attribute Feature
Simple type="simple" or no attribute All categories
Apparel type="vendor.model" Fields vendor, model, size grid
Books type="book" Fields author, publisher, ISBN
Media type="audiobook" Specific media fields

In most cases suppliers use simple type. Specific types appear in niche catalogs.

Development Timeline

Option Scope Timeline
Basic import Products, prices, categories 2–3 days
Complete with characteristics Param mapping to properties, images 4–5 days
Multi-supplier system UI, schedule, logs, deduplication 7–10 days