Как сконвертировать большой XML-каталог товаров в CSV

Aug 24, 2026

Есть типовая задача: поставщик отдаёт большой XML-фид с товарами, а на выходе нужен CSV определённой структуры, например для импорта в 1С или другую товаро-учётную систему.

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

Вместо того чтобы вручную разбирать XML, искать XPath для каждого поля и писать XSLT, эту работу можно отдать ИИ.

Схема получается такой:

XML-фид с товарами
        +
XLS со списком нужных полей
        ↓
       ИИ
        ↓
готовый XSL stylesheet
        ↓
 Oxygen XML Editor
        ↓
       CSV

Что понадобится

Нам нужны:

  • исходный XML-фид;
  • XLS или XLSX со списком полей, которые должны попасть в CSV;
  • Oxygen XML Editor;
  • ИИ-агент, которому можно передать XLS и фрагмент XML;
  • несколько минут на проверку результата.

Главная идея: мы не объясняем ИИ вручную, где находится каждое поле.

Мы даём ему:

  1. XLS со структурой итогового CSV;
  2. реальный пример одного товара из XML;
  3. родительские XML-элементы, чтобы модель могла определить правильный XPath;
  4. требования к формату CSV.

ИИ сам сопоставляет поля из XLS со структурой XML и генерирует готовый XSLT.


Шаг 1. Берём пример товара из XML

Допустим, исходный XML выглядит так:

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

<catalog>
    <products>

        <product id="10001">
            <sku>ABC-001</sku>
            <name>Кофемолка ручная</name>
            <brand>Example Brand</brand>

            <price currency="RUB">
                2490.00
            </price>

            <stock>17</stock>

            <category>
                <id>42</id>
                <name>Кухонная техника</name>
            </category>

            <dimensions>
                <width>120</width>
                <height>250</height>
                <depth>100</depth>
            </dimensions>

            <description>
                Стальная кофемолка, модель "Classic"; керамические жернова
            </description>
        </product>

    </products>
</catalog>

Для ИИ лучше передавать не только сам:

<product>

но и несколько уровней выше:

<catalog>
    <products>
        <product>
            ...
        </product>
    </products>
</catalog>

Тогда модель сможет определить точный XPath:

/catalog/products/product

а не будет гадать, где именно располагаются товары.


Шаг 2. Готовим XLS с нужными полями

Допустим, заказчик или внутренняя система требует CSV такой структуры:

ПолеОписание
idID товара
skuАртикул
nameНазвание
brandПроизводитель
priceЦена
category_idID категории
category_nameНазвание категории
stockОстаток
widthШирина
heightВысота
depthГлубина
descriptionОписание

На практике таких колонок может быть 50, 100 или несколько сотен.

Именно здесь ИИ особенно полезен.

Не нужно вручную писать:

@id
sku
name
brand
price
category/id
category/name
stock
dimensions/width
dimensions/height
dimensions/depth
description

Мы просто передаём XLS модели и просим найти соответствия самостоятельно.


Шаг 3. Отдаём XML и XLS ИИ

Загружаем в ИИ-агента:

  • XLS/XLSX со списком полей;
  • XML-файл либо фрагмент XML с одним полным товаром.

Если XML огромный, передавать весь файл обычно не нужно.

Для генерации stylesheet достаточно реального item с полной структурой.

Если структура товаров может различаться, лучше дать несколько примеров:

товар со всеми полями
товар с пустыми полями
товар с несколькими характеристиками
товар с несколькими изображениями

Промпт для ИИ

Используем следующий запрос:

У меня есть XML-фид с каталогом товаров и XLS/XLSX-файл, в котором описана структура итогового CSV.

Твоя задача — сгенерировать готовый XSLT 2.0 stylesheet для преобразования XML в CSV через Oxygen XML Editor.

Сначала проанализируй XLS-файл.

Каждая строка XLS описывает поле, которое должно присутствовать в итоговом CSV. Используй названия полей и их порядок из XLS.

После этого проанализируй предоставленный XML и самостоятельно найди соответствующий XPath для каждого поля из XLS.

Требования:

1. Определи точный XPath до элемента одного товара.

2. Для каждой колонки из XLS найди соответствующее значение в XML.

3. Не придумывай XML-элементы, которых нет в исходном XML.

4. Если однозначного соответствия для поля из XLS нет, оставь поле пустым и перед XSLT отдельно укажи, какие поля не удалось сопоставить.

5. Если поле находится в XML-атрибуте, используй атрибут.

6. Если поле находится во вложенном элементе, используй точный XPath до него.

7. Если XML использует namespace, обязательно учти его в stylesheet.

8. Не используй неоправданно широкие XPath вида //element, если можно построить точный путь относительно товара.

9. Один товар XML должен соответствовать одной строке CSV.

10. Порядок колонок CSV должен полностью соответствовать порядку полей в XLS.

11. Первая строка CSV должна содержать названия полей из XLS.

12. Разделитель CSV — точка с запятой (;).

13. Все значения заключай в двойные кавычки.

14. Двойные кавычки внутри значения экранируй по правилам CSV: заменяй " на "".

15. Переводы строк и лишние пробелы внутри текстовых значений нормализуй, чтобы один товар всегда занимал одну строку CSV.

16. Если значение отсутствует, выводи пустую CSV-ячейку.

17. Кодировка результата — UTF-8.

18. Результат XSLT должен использовать:
<xsl:output method="text" encoding="UTF-8"/>

19. Не добавляй XML declaration в CSV.

20. Используй XSLT 2.0, совместимый с Oxygen XML Editor.

21. Если в XML есть повторяющиеся элементы, например images, params, categories или warehouse, выбери разумный способ их представления в одной CSV-ячейке. Если способ нельзя определить однозначно из XLS, укажи это перед кодом.

22. Не меняй названия колонок, указанные в XLS.

23. Не пропускай поля из XLS, даже если соответствующего значения нет в XML.

24. Перед генерацией XSLT выведи таблицу соответствий:

CSV field | XML XPath | комментарий

25. После таблицы выведи полный готовый XSLT одним блоком кода.

26. Не используй псевдокод и не сокращай stylesheet.

27. XSLT должен быть готов к сохранению в файл .xsl и непосредственному запуску в Oxygen XML Editor.

XML-фрагмент с примером товара приложен отдельно.

XLS/XLSX со списком полей приложен отдельно.

После этого ИИ должен построить таблицу примерно такого вида:

id             → @id
sku            → sku
name           → name
brand          → brand
price          → price
category_id    → category/id
category_name  → category/name
stock          → stock
width          → dimensions/width
height         → dimensions/height
depth          → dimensions/depth
description    → description

А затем сгенерировать готовый stylesheet.


Пример полученного XSLT

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

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

<xsl:stylesheet
    version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:f="urn:csv-functions"
    exclude-result-prefixes="xs f">

    <xsl:output
        method="text"
        encoding="UTF-8"
        omit-xml-declaration="yes"/>

    <xsl:function name="f:csv" as="xs:string">
        <xsl:param name="value"/>

        <xsl:variable
            name="text"
            select="normalize-space(string($value))"/>

        <xsl:sequence
            select="
                concat(
                    '&quot;',
                    replace($text, '&quot;', '&quot;&quot;'),
                    '&quot;'
                )
            "/>
    </xsl:function>

    <xsl:template match="/">

        <xsl:text>"id";"sku";"name";"brand";"price";"category_id";"category_name";"stock";"width";"height";"depth";"description"</xsl:text>
        <xsl:text>&#13;&#10;</xsl:text>

        <xsl:for-each select="/catalog/products/product">

            <xsl:value-of select="f:csv(@id)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(sku)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(name)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(brand)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(price)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(category/id)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(category/name)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(stock)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(dimensions/width)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(dimensions/height)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(dimensions/depth)"/>
            <xsl:text>;</xsl:text>

            <xsl:value-of select="f:csv(description)"/>

            <xsl:text>&#13;&#10;</xsl:text>

        </xsl:for-each>

    </xsl:template>

</xsl:stylesheet>

Сохраняем результат в файл:

catalog-to-csv.xsl

Почему лучше давать ИИ именно XLS

Можно вручную перечислить поля в промпте:

id
sku
name
price
...

Но при большом количестве колонок XLS удобнее.

Во-первых, он уже является формальной спецификацией итогового файла.

Во-вторых, в нём могут находиться дополнительные данные:

название поля
описание
тип
обязательность
пример значения
комментарий

Например:

fielddescriptionrequired
product_idУникальный IDyes
vendor_codeАртикул производителяyes
brandПроизводительno
priceЦенаyes

Для ИИ это дополнительный контекст.

Если в XML одновременно есть:

<id>123</id>
<vendorCode>ABC-123</vendorCode>
<manufacturerCode>XYZ-777</manufacturerCode>

описание из XLS помогает понять, какое именно значение необходимо поставить в vendor_code.


Что делать со сложными полями

Реальные товарные XML редко состоят только из простых элементов.

Например:

<product>
    <params>
        <param name="Цвет">Чёрный</param>
        <param name="Материал">Сталь</param>
        <param name="Страна">Германия</param>
    </params>
</product>

А в XLS есть колонка:

color

ИИ должен определить, что значение нужно брать из:

params/param[@name='Цвет']

В stylesheet получится:

<xsl:value-of
    select="f:csv(params/param[@name='Цвет'])"/>

Аналогично можно извлекать значения из атрибутов.

Например:

<price currency="RUB">2490</price>

Если в XLS есть:

price
currency

XPath будут:

price
price/@currency

Повторяющиеся значения

Другой распространённый вариант:

<images>
    <image>https://example.com/1.jpg</image>
    <image>https://example.com/2.jpg</image>
    <image>https://example.com/3.jpg</image>
</images>

При этом в XLS есть одна колонка:

images

В таком случае можно попросить ИИ объединять значения через выбранный разделитель.

Например:

https://example.com/1.jpg|https://example.com/2.jpg|https://example.com/3.jpg

Для XSLT 2.0 это можно сделать через:

<xsl:value-of
    select="f:csv(string-join(images/image, '|'))"/>

То же самое работает с:

  • категориями;
  • изображениями;
  • характеристиками;
  • штрихкодами;
  • складами;
  • совместимыми моделями;
  • альтернативными артикулами.

Важно только явно определить, как повторяющиеся значения должны выглядеть в одной CSV-ячейке.


Если XML использует namespace

Например:

<catalog xmlns="https://example.com/catalog">

В таком XML XPath:

/catalog/products/product

может ничего не найти.

В stylesheet namespace необходимо объявить:

<xsl:stylesheet
    version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:c="https://example.com/catalog"
    exclude-result-prefixes="c">

После этого XPath будет выглядеть так:

<xsl:for-each
    select="/c:catalog/c:products/c:product">

Поэтому в промпте отдельно указано требование:

Если XML использует namespace, обязательно учти его.

Проверяем сгенерированный stylesheet

Полностью доверять генерации кода не стоит.

Перед запуском на полном каталоге достаточно проверить несколько вещей.

XPath товара

Например:

<xsl:for-each select="/catalog/products/product">

Он должен вести ровно к одному item товара.

Количество колонок

Количество полей в заголовке:

"id";"sku";"name";"brand";...

должно совпадать с количеством значений в каждой строке.

Порядок колонок

Он должен полностью соответствовать XLS.

Поля без соответствия

Если в XLS есть поле, которого нет в XML, колонка всё равно должна присутствовать.

Например:

manufacturer_country

Если источник такого значения отсутствует, в CSV должно быть:

""

а не смещение всех последующих колонок.

Кавычки

XML:

<name>Кофеварка "Barista Pro"</name>

CSV:

"Кофеварка ""Barista Pro"""

Переносы строк

XML:

<description>
    Кофеварка для дома.
    Давление 15 бар.
</description>

В CSV это должно остаться одной строкой.


Настраиваем Oxygen XML Editor

Открываем исходный XML-фид в Oxygen XML Editor.

Нажимаем:

Ctrl + Shift + C

или открываем:

Document
→ Transformation
→ Configure Transformation Scenario(s)

Создаём новый сценарий:

New
→ XML transformation with XSLT

В поле:

XSL URL

выбираем сгенерированный файл:

catalog-to-csv.xsl

[СКРИНШОТ: Configure Transformation Scenario — поле XSL URL]


Указываем путь для CSV

Переходим во вкладку:

Output

В поле:

Save As

указываем полный путь.

Например:

C:/Users/<NAME>/Downloads/${cfn}.csv

${cfn} — имя текущего XML-файла без расширения.

Если исходный файл:

supplier-feed.xml

результат будет:

supplier-feed.csv

Можно сохранять CSV рядом с XML:

${cfd}/${cfn}.csv

[СКРИНШОТ: вкладка Output — поле Save As]


Запускаем Transformation

После сохранения сценария запускаем преобразование.

Oxygen:

читает XML
    ↓
применяет XSLT
    ↓
проходит по каждому товару
    ↓
извлекает поля, описанные в XLS
    ↓
формирует строки CSV
    ↓
сохраняет файл

На выходе получаем:

"id";"sku";"name";"brand";"price";"category_id";"category_name";"stock";"width";"height";"depth";"description"
"10001";"ABC-001";"Кофемолка ручная";"Example Brand";"2490.00";"42";"Кухонная техника";"17";"120";"250";"100";"Стальная кофемолка, модель ""Classic""; керамические жернова"

Сначала тестируем на нескольких товарах

На новый stylesheet не стоит сразу натравливать XML размером в несколько гигабайт.

Сначала делаем небольшой тестовый файл из нескольких товаров.

Хорошо, если там будут:

  • полностью заполненный товар;
  • товар с отсутствующими полями;
  • кавычки в названии;
  • переносы строк;
  • пустой элемент;
  • несколько изображений;
  • несколько характеристик;
  • значения в атрибутах;
  • длинное описание.

После этого проверяем:

заголовок CSV
количество колонок
порядок колонок
первые строки
пустые значения
кавычки
повторяющиеся элементы

И только после этого запускаем Transformation на полном каталоге.


Что получается в итоге

Весь процесс сводится к следующему:

1. Получаем XML-фид.

2. Получаем XLS со спецификацией полей.

3. Берём из XML один или несколько реальных товаров.

4. Передаём ИИ:
   - XLS;
   - XML-фрагмент;
   - промпт для генерации XSLT.

5. ИИ:
   - читает структуру XLS;
   - определяет список колонок;
   - анализирует XML;
   - сопоставляет поля;
   - строит XPath;
   - генерирует stylesheet.

6. Сохраняем результат как:
   catalog-to-csv.xsl

7. Открываем XML в Oxygen.

8. Нажимаем:
   Ctrl + Shift + C

9. Создаём:
   XML transformation with XSLT

10. Указываем XSL URL.

11. Во вкладке Output задаём:
    C:/Users/<NAME>/Downloads/${cfn}.csv

12. Запускаем Transformation.

13. Получаем CSV.

В результате XLS становится фактически спецификацией результата, XML — источником данных, а ИИ берёт на себя наиболее рутинную часть работы: сопоставление десятков или сотен полей и генерацию XPath/XSLT.

Для каждого нового поставщика остаётся заменить XML-пример и его спецификацию XLS, после чего сгенерировать новый stylesheet под конкретную структуру фида.