December 23, 2012

Своя выгрузка в Яндекс.Маркет с 1С-Битрикс

Всем привет!

Сегодня я расскажу такую интересную тему как выгрузка каталога товаров из Битрикс в Яндекс.Маркет.

Вообще этот вопрос довольно подробно рассмотрен в официальной документации, да и все там интуитивно понятно.

Но разбирать мы будем нетривиальный случай - на одном интернет-магазине потребовалось сделать выгрузку товаров в Яндекс.Маркет, товары там хранятся в одном инфоблоке, а торговые предложения к ним в другом. Как оказалось - функционал выгрузки в маркет из подобной конфигурации с двумя инфоблоками появился сравнительно недавно (осенью 2011), а на сайте уже летом прошлого года закончилась лицензия на обновления. Поэтому пришлось как то выкручиваться.

Вариант 1 - не прокатил

Взять профили выгрузки(/bitrix/php_interface/include/catalog_export/) из новой редакции. Оно даже запустилось, но при попытке выгрузки пошли ошибки - скрипт не находил в старом каталоге новые функции.

Вариант 2 - не стал пробовать

Взять лицензионный код с другого проекта и вставив его обновиться - не стал делать из-за соображений легальности данного метода и риска блокировки лицензионных ключиков

Вариант 3 - успешно

На сей раз я решил переписать стандартный профиль выгрузки добавив в него код импорта цен с инфоблока торговых предложений. Решение быстрое, потому ID инфоблоков прописаны прямо в коде, а для каждого товара выгружается только одно предложение (к слову сказать на том сайте для каждого товара и так только по одному предложению).

За основу я взял файлы yandex_run.php и yandex_setup.php, скопировал их в main_run.php и main_setup.php. В каждом файле во второй строчке прописываем название профиля:

//<title>Main Yandex</title>

Ну а теперь листинг main_run.php с моими комментариями:

<?php
//<title>Main Yandex</title>
set_time_limit(0);
global $USER, $APPLICATION;
$bTmpUserCreated = False;
if (!isset($USER) || !is_a($GLOBALS['USER'], 'CUser')) {
    $bTmpUserCreated = True;
    if (isset($USER)) {
        $USER_TMP = $USER;
    }

    $USER = new CUser();
}
$arYandexFields = array(
    'vendor',
    'vendorCode',
    'model',
    'author',
    'name',
    'publisher',
    'year',
    'ISBN',
    'volume',
    'part',
    'language',
    'binding',
    'page_extent',
    'table_of_contents',
    'performed_by',
    'performance_type',
    'storage',
    'format',
    'recording_length',
    'series',
    'artist',
    'title',
    'year',
    'media',
    'starring',
    'director',
    'originalName',
    'country',
    'description',
    'sales_notes',
    'promo',
    'aliases',
    'provider',
    'tarifplan',
    'xCategory',
    'additional',
    'worldRegion',
    'region',
    'days',
    'dataTour',
    'hotel_stars',
    'room',
    'meal',
    'included',
    'transport',
    'price_min',
    'price_max',
    'options',
    'manufacturer_warranty',
    'country_of_origin',
    'downloadable',
    'param',
    'place',
    'hall',
    'hall_part',
    'is_premiere',
    'is_kids',
    'date'
);
if (!function_exists("yandex_replace_special")) {
    function yandex_replace_special($arg)
    {
        if (in_array($arg[0], array(
            "\"",
            "&",
            "<",
            ">"
        )))
            return $arg[0];
        else
            return " ";
    }
}
if (!function_exists("yandex_text2xml")) {
    function yandex_text2xml($text, $bHSC = false)
    {
        $text = $GLOBALS['APPLICATION']->ConvertCharset($text, LANG_CHARSET, 'windows-1251');

        if ($bHSC)
            $text = htmlspecialchars($text);
        $text = preg_replace("/[\x1-\x8\xB-\xC\xE-\x1F]/", "", $text);
        $text = str_replace("'", "'", $text);
        return $text;
    }
}
if (!function_exists('yandex_get_value')) {
    function yandex_get_value($arOffer, $param, $PROPERTY)
    {
        global $IBLOCK_ID;
        static $arProperties = null, $arUserTypes = null;

        if (!is_array($arProperties)) {
            $dbRes = CIBlockProperty::GetList(array(
                'id' => 'asc'
            ), array(
                'IBLOCK_ID' => $IBLOCK_ID,
                'CHECK_PERMISSIONS' => 'N'
            ));

            while ($arRes = $dbRes->Fetch()) {
                $arProperties[$arRes['ID']] = $arRes;
            }
        }

        $strProperty = '';
        $bParam      = substr($param, 0, 6) == 'PARAM_';
        if (is_array($arProperties[$PROPERTY])) {
            $PROPERTY_CODE = $arProperties[$PROPERTY]['CODE'];

            $arProperty = $arOffer['PROPERTIES'][$PROPERTY_CODE] ? $arOffer['PROPERTIES'][$PROPERTY_CODE] : $arOffer['PROPERTIES'][$PROPERTY];

            $value       = '';
            $description = '';
            switch ($arProperties[$PROPERTY]['PROPERTY_TYPE']) {
                case 'E':
                    $dbRes = CIBlockElement::GetList(array(), array(
                        'IBLOCK_ID' => $arProperties[$PROPERTY]['LINK_IBLOCK_ID'],
                        'ID' => $arProperty['VALUE']
                    ), false, false, array(
                        'NAME'
                    ));
                    while ($arRes = $dbRes->Fetch()) {
                        $value .= ($value ? ', ' : '') . $arRes['NAME'];
                    }
                    break;
                case 'G':
                    $dbRes = CIBlockSection::GetList(array(), array(
                        'IBLOCK_ID' => $arProperty['LINK_IBLOCK_ID'],
                        'ID' => $arProperty['VALUE']
                    ));
                    while ($arRes = $dbRes->Fetch()) {
                        $value .= ($value ? ', ' : '') . $arRes['NAME'];
                    }
                    break;
                case 'L':
                    if ($arProperty['VALUE']) {
                        if (is_array($arProperty['VALUE']))
                            $value .= implode(', ', $arProperty['VALUE']);
                        else
                            $value .= $arProperty['VALUE'];
                    }
                    break;

                default:
                    if ($bParam && $arProperty['WITH_DESCRIPTION'] == 'Y') {
                        $description = $arProperty['DESCRIPTION'];
                        $value       = $arProperty['VALUE'];
                    } else {
                        $value = is_array($arProperty['VALUE']) ? implode(', ', $arProperty['VALUE']) : $arProperty['VALUE'];
                    }
            }

            // !!!! check multiple properties and properties like CML2_ATTRIBUTES

            if ($bParam) {
                if (is_array($description)) {
                    foreach ($value as $key => $val) {
                        $strProperty .= $strProperty ? "\n" : "";
                        $strProperty .= '<param name="' . yandex_text2xml($description[$key], true) . '">' . yandex_text2xml($val) . '</param>';
                    }
                } else {
                    $strProperty .= '<param name="' . yandex_text2xml($arProperties[$PROPERTY]['NAME'], true) . '">' . yandex_text2xml($value) . '</param>';
                }
            } else {
                $param_h = yandex_text2xml($param, true);
                $strProperty .= '<' . $param_h . '>' . yandex_text2xml($value) . '</' . $param_h . '>';
            }
        }
        return $strProperty;
        //if (is_callable(array($arParams["arUserField"]["USER_TYPE"]['CLASS_NAME'], 'getlist')))
    }
}
$strExportErrorMessage = "";
if ($XML_DATA && CheckSerializedData($XML_DATA)) {
    $XML_DATA = unserialize(stripslashes($XML_DATA));
    if (!is_array($XML_DATA))
        $XML_DATA = array();
}
$GLOBALS['IBLOCK_ID'] = IntVal($IBLOCK_ID);
//HAMDEEW: Инфоблок торговых предложений
$td_iblock_id         = 42; //мои правки
$db_iblock            = CIBlock::GetByID($IBLOCK_ID);
if (!($ar_iblock = $db_iblock->Fetch()))
    $strExportErrorMessage .= "Information block #" . $IBLOCK_ID . " does not exist.\n";
else {
    $SETUP_SERVER_NAME = trim($SETUP_SERVER_NAME);
    if (strlen($SETUP_SERVER_NAME) <= 0) {
        if (strlen($ar_iblock['SERVER_NAME']) <= 0) {
            $rsSite = CSite::GetList(($b = "sort"), ($o = "asc"), array(
                "LID" => $ar_iblock["LID"]
            ));
            if ($arSite = $rsSite->Fetch())
                $ar_iblock["SERVER_NAME"] = $arSite["SERVER_NAME"];
            if (strlen($ar_iblock["SERVER_NAME"]) <= 0 && defined("SITE_SERVER_NAME"))
                $ar_iblock["SERVER_NAME"] = SITE_SERVER_NAME;
            if (strlen($ar_iblock["SERVER_NAME"]) <= 0)
                $ar_iblock["SERVER_NAME"] = COption::GetOptionString("main", "server_name", "");
        }
    } else {
        $ar_iblock['SERVER_NAME'] = $SETUP_SERVER_NAME;
    }
}
if (strlen($strExportErrorMessage) <= 0) {
    $bAllSections = False;
    $arSections   = array();
    if (is_array($V)) {
        foreach ($V as $key => $value) {
            if (trim($value) == "0") {
                $bAllSections = True;
                break;
            }

            if (IntVal($value) > 0) {
                $arSections[] = IntVal($value);
            }
        }
    }
    if (!$bAllSections && count($arSections) <= 0)
        $strExportErrorMessage .= "Section list is not set.\n";
}
$SETUP_FILE_NAME = Rel2Abs("/", $SETUP_FILE_NAME);
/*
if (strtolower(substr($SETUP_FILE_NAME, strlen($SETUP_FILE_NAME)-4)) != ".csv")
$SETUP_FILE_NAME .= ".csv";
*/
if (!$bTmpUserCreated && $GLOBALS["APPLICATION"]->GetFileAccessPermission($SETUP_FILE_NAME) < "W")
    $strExportErrorMessage .= str_replace("#FILE#", $SETUP_FILE_NAME, "Not enough access rights to replace file #FILE#") . "
";
if (strlen($strExportErrorMessage) <= 0) {
    CheckDirPath($_SERVER["DOCUMENT_ROOT"] . $SETUP_FILE_NAME);

    if (!$fp = @fopen($_SERVER["DOCUMENT_ROOT"] . $SETUP_FILE_NAME, "wb")) {
        $strExportErrorMessage .= "Can not open \"" . $_SERVER["DOCUMENT_ROOT"] . $SETUP_FILE_NAME . "\" file for writing.\n";
    } else {

        if (!@fwrite($fp, '<?if (!isset($_GET["referer1"]) || strlen($_GET["referer1"])<=0) $_GET["referer1"] = "yandext";?>')) {
            $strExportErrorMessage .= "Can not write in \"" . $_SERVER["DOCUMENT_ROOT"] . $SETUP_FILE_NAME . "\" file.\n";
            @fclose($fp);
        } else {
            fwrite($fp, '<?if (!isset($_GET["referer2"])) $_GET["referer2"] = "";?>');
        }
    }
}
if (strlen($strExportErrorMessage) <= 0) {
    @fwrite($fp, '<? header("Content-Type: text/xml; charset=windows-1251");?>');
    @fwrite($fp, '<? echo "<"."?xml version=\"1.0\" encoding=\"windows-1251\"?".">"?>');
    @fwrite($fp, "\n<!DOCTYPE yml_catalog SYSTEM \"shops.dtd\">\n");
    @fwrite($fp, "<yml_catalog date=\"" . Date("Y-m-d H:i") . "\">\n");
    @fwrite($fp, "<shop>\n");
    @fwrite($fp, "<name>" . htmlspecialchars($APPLICATION->ConvertCharset(COption::GetOptionString("main", "site_name", ""), LANG_CHARSET, 'windows-1251')) . "</name>\n");
    @fwrite($fp, "<company>" . htmlspecialchars($APPLICATION->ConvertCharset(COption::GetOptionString("main", "site_name", ""), LANG_CHARSET, 'windows-1251')) . "</company>\n");
    @fwrite($fp, "<url>http://" . htmlspecialchars($ar_iblock['SERVER_NAME']) . "</url>\n");
    $strTmp = "<currencies>\n";
    if ($arCurrency = CCurrency::GetByID('RUR'))
        $RUR = 'RUR';
    else
        $RUR = 'RUB';
    $arCurrencyAllowed = array(
        $RUR,
        'USD',
        'EUR',
        'UAH',
        'BYR',
        'KZT'
    );
    $BASE_CURRENCY     = CCurrency::GetBaseCurrency();
    if (is_array($XML_DATA['CURRENCY'])) {
        foreach ($XML_DATA['CURRENCY'] as $CURRENCY => $arCurData) {
            if (in_array($CURRENCY, $arCurrencyAllowed)) {
                $strTmp .= "<currency id=\"" . $CURRENCY . "\"" . " rate=\"" . ($arCurData['rate'] == 'SITE' ? CCurrencyRates::ConvertCurrency(1, $CURRENCY, $RUR) : $arCurData['rate']) . "\"" . ($arCurData['plus'] > 0 ? ' plus="' . intval($arCurData['plus']) . '"' : '') . " />\n";
            }
        }
    } else {
        $db_acc = CCurrency::GetList(($by = "sort"), ($order = "asc"));
        while ($arAcc = $db_acc->Fetch()) {
            if (in_array($arAcc['CURRENCY'], $arCurrencyAllowed))
                $strTmp .= "<currency id=\"" . $arAcc["CURRENCY"] . "\" rate=\"" . (CCurrencyRates::ConvertCurrency(1, $arAcc["CURRENCY"], $RUR)) . "\"/>\n";
        }
    }
    $strTmp .= "</currencies>\n";
    @fwrite($fp, $strTmp);
    //*****************************************//
    $arSelect = array(
        "ID",
        "LID",
        "IBLOCK_ID",
        "IBLOCK_SECTION_ID",
        "ACTIVE",
        "ACTIVE_FROM",
        "ACTIVE_TO",
        "NAME",
        "PREVIEW_PICTURE",
        "PREVIEW_TEXT",
        "PREVIEW_TEXT_TYPE",
        "DETAIL_PICTURE",
        "LANG_DIR",
        "DETAIL_PAGE_URL"
    );

    $db_res   = CCatalogGroup::GetGroupsList(array(
        "GROUP_ID" => 2
    ));
    $arPTypes = array();
    while ($ar_res = $db_res->Fetch()) {
        if (!in_array($ar_res["CATALOG_GROUP_ID"], $arPTypes)) {
            $arPTypes[] = $ar_res["CATALOG_GROUP_ID"];
            $arSelect[] = "CATALOG_GROUP_" . $ar_res["CATALOG_GROUP_ID"];
        }
    }

    $strTmpCat     = "";
    $strTmpOff     = "";
    $arAvailGroups = array();
    if (!$bAllSections) {
        for ($i = 0; $i < count($arSections); $i++) {
            $filter_tmp      = $filter;
            $db_res          = CIBlockSection::GetNavChain($IBLOCK_ID, $arSections[$i]);
            $curLEFT_MARGIN  = 0;
            $curRIGHT_MARGIN = 0;
            while ($ar_res = $db_res->Fetch()) {
                $curLEFT_MARGIN  = IntVal($ar_res["LEFT_MARGIN"]);
                $curRIGHT_MARGIN = IntVal($ar_res["RIGHT_MARGIN"]);
                $arAvailGroups[] = array(
                    "ID" => IntVal($ar_res["ID"]),
                    "IBLOCK_SECTION_ID" => IntVal($ar_res["IBLOCK_SECTION_ID"]),
                    "NAME" => $ar_res["NAME"]
                );
            }
            $filter = Array(
                "IBLOCK_ID" => $IBLOCK_ID,
                ">LEFT_MARGIN" => $curLEFT_MARGIN,
                "<RIGHT_MARGIN" => $curRIGHT_MARGIN,
                "ACTIVE" => "Y",
                "IBLOCK_ACTIVE" => "Y",
                "GLOBAL_ACTIVE" => "Y"
            );
            $db_res = CIBlockSection::GetList(array(
                "left_margin" => "asc"
            ), $filter);
            while ($ar_res = $db_res->Fetch()) {
                $arAvailGroups[] = array(
                    "ID" => IntVal($ar_res["ID"]),
                    "IBLOCK_SECTION_ID" => IntVal($ar_res["IBLOCK_SECTION_ID"]),
                    "NAME" => $ar_res["NAME"]
                );
            }
        }
        $cnt_arAvailGroups = count($arAvailGroups);
        for ($i = 0; $i < $cnt_arAvailGroups - 1; $i++) {
            if (!isset($arAvailGroups[$i]))
                continue;
            for ($j = $i + 1; $j < $cnt_arAvailGroups; $j++) {
                if (!isset($arAvailGroups[$j]))
                    continue;
                if ($arAvailGroups[$i]["ID"] == $arAvailGroups[$j]["ID"]) {
                    unset($arAvailGroups[$j]);
                }
            }
        }
    } else {
        $filter = Array(
            "IBLOCK_ID" => $IBLOCK_ID,
            "ACTIVE" => "Y",
            "IBLOCK_ACTIVE" => "Y",
            "GLOBAL_ACTIVE" => "Y"
        );
        $db_res = CIBlockSection::GetList(array(
            "left_margin" => "asc"
        ), $filter);
        while ($ar_res = $db_res->Fetch()) {
            $arAvailGroups[] = array(
                "ID" => IntVal($ar_res["ID"]),
                "IBLOCK_SECTION_ID" => IntVal($ar_res["IBLOCK_SECTION_ID"]),
                "NAME" => $ar_res["NAME"]
            );
        }
    }
    $arSectionIDs = array();
    foreach ($arAvailGroups as $key => $value) {
        $strTmpCat .= "<category id=\"" . $value["ID"] . "\"" . (IntVal($value["IBLOCK_SECTION_ID"]) > 0 ? " parentId=\"" . $value["IBLOCK_SECTION_ID"] . "\"" : "") . ">" . yandex_text2xml($value["NAME"], true) . "</category>\n";
        $arSectionIDs[] = $value["ID"];
    }
    //*****************************************//
    $filter = Array(
        "IBLOCK_ID" => $IBLOCK_ID,
        "ACTIVE_DATE" => "Y",
        "ACTIVE" => "Y"
    );
    if (!$bAllSections) {
        $filter["INCLUDE_SUBSECTIONS"] = "Y";
        $filter["SECTION_ID"]          = $arSectionIDs;
    }
    $res    = CIBlockElement::GetList(array(), $filter, false, false, $arSelect);
    $db_acc = new CIBlockResult($res);

    $total_sum = 0;
    $is_exists = false;
    $cnt       = 0;
    $iii       = 0;
    while ($obElement = $db_acc->GetNextElement()) {
        $arAcc    = $obElement->GetFields();
        //HAMDEEW: Правки начало
        $rsOffers = CIBlockElement::GetList(array(
            'ID'
        ), array(
            'IBLOCK_ID' => $td_iblock_id,
            'PROPERTY_CML2_LINK' => $arAcc["ID"]
        ));
        if ($arOffer = $rsOffers->GetNext()) {
            $arAcc2 = $arOffer;
        }
        //HAMDEEW: Правки конец


        if (is_array($XML_DATA['XML_DATA'])) {
            $arAcc["PROPERTIES"] = $obElement->GetProperties();
        }

        $str_QUANTITY       = DoubleVal($arAcc["CATALOG_QUANTITY"]);
        $str_QUANTITY_TRACE = $arAcc["CATALOG_QUANTITY_TRACE"];
        if (($str_QUANTITY <= 0) && ($str_QUANTITY_TRACE == "Y"))
            $str_AVAILABLE = ' available="false"';
        else
            $str_AVAILABLE = ' available="true"';
        // TODO: use PRICE setting. this code is only for PRICE=0
        $minPrice         = 0;
        $minPriceRUR      = 0;
        $minPriceGroup    = 0;
        $minPriceCurrency = "";
        if ($XML_DATA['PRICE'] > 0) {
            $minPrice         = $arAcc["CATALOG_PRICE_" . $XML_DATA['PRICE']];
            $minPriceGroup    = $XML_DATA['PRICE'];
            $minPriceCurrency = $arAcc["CATALOG_CURRENCY_" . $XML_DATA['PRICE']];
            $minPriceRUR      = CCurrencyRates::ConvertCurrency($arAcc["CATALOG_PRICE_" . $XML_DATA['PRICE']], $arAcc["CATALOG_CURRENCY_" . $XML_DATA['PRICE']], $RUR);
        } else {
            if ($arPrice = CCatalogProduct::GetOptimalPrice(
            //HAMDEEW: Правки начало
                $arAcc2['ID'], //вот здесь я поменял!

            //HAMDEEW: Правки конец
                1, array(
                2
            ), // anonymous
                'N', array(), $ar_iblock['LID'])) {
                $minPrice         = $arPrice['DISCOUNT_PRICE'];
                $minPriceCurrency = $BASE_CURRENCY;
                $minPriceRUR      = CCurrencyRates::ConvertCurrency($minPrice, $BASE_CURRENCY, $RUR);
                $minPriceGroup    = $arPrice['PRICE']['CATALOG_GROUP_ID'];
            }
        }
        if ($minPrice <= 0)
            continue;
        $bNoActiveGroup = True;
        $strTmpOff_tmp  = "";
        $db_res1        = CIBlockElement::GetElementGroups($arAcc["ID"]);
        while ($ar_res1 = $db_res1->Fetch()) {
            if (in_array(IntVal($ar_res1["ID"]), $arSectionIDs)) {
                $strTmpOff_tmp .= "<categoryId>" . $ar_res1["ID"] . "</categoryId>\n";
                $bNoActiveGroup = False;
            }
        }
        if ($bNoActiveGroup)
            continue;
        if (strlen($arAcc['DETAIL_PAGE_URL']) <= 0)
            $arAcc['DETAIL_PAGE_URL'] = '/';
        else
            $arAcc['DETAIL_PAGE_URL'] = str_replace(' ', '%20', $arAcc['DETAIL_PAGE_URL']);

        if (is_array($XML_DATA) && $XML_DATA['TYPE'] && $XML_DATA['TYPE'] != 'none')
            $str_TYPE = ' type="' . htmlspecialchars($XML_DATA['TYPE']) . '"';
        else
            $strType = '';

        $strTmpOff .= "<offer id=\"" . $arAcc["ID"] . "\"" . $str_TYPE . $str_AVAILABLE . ">\n";
        $strTmpOff .= "<url>http://" . $ar_iblock['SERVER_NAME'] . htmlspecialchars($arAcc["~DETAIL_PAGE_URL"]) . (strstr($arAcc['DETAIL_PAGE_URL'], '?') === false ? '?' : '&') . "r1=<?echo \$_GET[\"referer1\"] ?>&r2=<?echo \$_GET[\"referer2\"] ?></url>\n";
        $strTmpOff .= "<price>" . $minPrice . "</price>\n";
        $strTmpOff .= "<currencyId>" . $minPriceCurrency . "</currencyId>\n";
        $strTmpOff .= $strTmpOff_tmp;
        if (IntVal($arAcc["DETAIL_PICTURE"]) > 0 || IntVal($arAcc["PREVIEW_PICTURE"]) > 0) {
            $pictNo = IntVal($arAcc["DETAIL_PICTURE"]);
            if ($pictNo <= 0)
                $pictNo = IntVal($arAcc["PREVIEW_PICTURE"]);
            $db_file = CFile::GetByID($pictNo);
            if ($ar_file = $db_file->Fetch()) {
                $strFile = "/" . (COption::GetOptionString("main", "upload_dir", "upload")) . "/" . $ar_file["SUBDIR"] . "/" . $ar_file["FILE_NAME"];
                $strFile = str_replace("//", "/", $strFile);
                $strTmpOff .= "<picture>http://" . $ar_iblock['SERVER_NAME'] . implode("/", array_map("rawurlencode", explode("/", $strFile))) . "</picture>\n";
            }
        }
        $y = 0;
        foreach ($arYandexFields as $key) {
            switch ($key) {
                case 'name':
                    if (is_array($XML_DATA) && ($XML_DATA['TYPE'] == 'vendor.model' || $XML_DATA['TYPE'] == 'artist.title'))
                        continue;

                    $strTmpOff .= "<name>" . yandex_text2xml($arAcc["NAME"], true) . "</name>\n";
                    break;
                case 'description':
                    $strTmpOff .= "<description>" . yandex_text2xml(TruncateText(($arAcc["PREVIEW_TEXT_TYPE"] == "html" ? strip_tags(preg_replace_callback("'&[^;]*;'", "yandex_replace_special", $arAcc["~PREVIEW_TEXT"])) : $arAcc["PREVIEW_TEXT"]), 255), true) . "</description>\n";
                    break;
                case 'param':
                    if (is_array($XML_DATA) && is_array($XML_DATA['XML_DATA']) && is_array($XML_DATA['XML_DATA']['PARAMS'])) {
                        foreach ($XML_DATA['XML_DATA']['PARAMS'] as $key => $prop_id) {
                            if ($prop_id) {
                                $strTmpOff .= yandex_get_value($arAcc, 'PARAM_' . $key, $prop_id) . "\n";
                            }
                        }
                    }
                    break;

                case 'model':
                case 'title':
                    if (!is_array($XML_DATA) || !is_array($XML_DATA['XML_DATA']) || !$XML_DATA['XML_DATA'][$key]) {
                        if ($key == 'model' && $XML_DATA['TYPE'] == 'vendor.model' || $key == 'title' && $XML_DATA['TYPE'] == 'artist.title')
                            $strTmpOff .= "<" . $key . ">" . yandex_text2xml($arAcc["NAME"], true) . "</" . $key . ">\n";
                    } else
                        $strTmpOff .= yandex_get_value($arAcc, $key, $XML_DATA['XML_DATA'][$key]);
                    break;

                case 'year':
                    $y++;
                    if ($XML_DATA['TYPE'] == 'artist.title') {
                        if ($y == 1)
                            continue;
                    } else {
                        if ($y > 1)
                            continue;
                    }

                // no break here

                default:
                    if (is_array($XML_DATA) && is_array($XML_DATA['XML_DATA']) && $XML_DATA['XML_DATA'][$key])
                        $strTmpOff .= yandex_get_value($arAcc, $key, $XML_DATA['XML_DATA'][$key]) . "\n";
            }
        }

        $strTmpOff .= "</offer>\n";
    }

    @fwrite($fp, "<categories>\n");
    @fwrite($fp, $strTmpCat);
    @fwrite($fp, "</categories>\n");
    @fwrite($fp, "<offers>\n");
    @fwrite($fp, $strTmpOff);
    @fwrite($fp, "</offers>\n");
    @fwrite($fp, "</shop>\n");
    @fwrite($fp, "</yml_catalog>\n");
    @fclose($fp);
}
if ($bTmpUserCreated) {
    unset($USER);

    if (isset($USER_TMP)) {
        $USER = $USER_TMP;
        unset($USER_TMP);
    }
}
?>