Как сконвертировать большой XML-каталог товаров в CSV
Есть типовая задача: поставщик отдаёт большой XML-фид с товарами, а на выходе нужен CSV определённой структуры, например для импорта в 1С или другую товаро-учётную систему.
При этом список необходимых полей уже описан в XLS-файле: названия колонок, их порядок, иногда комментарии и требования к заполнению.
Вместо того чтобы вручную разбирать XML, искать XPath для каждого поля и писать XSLT, эту работу можно отдать ИИ.
Схема получается такой:
XML-фид с товарами
+
XLS со списком нужных полей
↓
ИИ
↓
готовый XSL stylesheet
↓
Oxygen XML Editor
↓
CSV
Что понадобится
Нам нужны:
- исходный XML-фид;
- XLS или XLSX со списком полей, которые должны попасть в CSV;
- Oxygen XML Editor;
- ИИ-агент, которому можно передать XLS и фрагмент XML;
- несколько минут на проверку результата.
Главная идея: мы не объясняем ИИ вручную, где находится каждое поле.
Мы даём ему:
- XLS со структурой итогового CSV;
- реальный пример одного товара из XML;
- родительские XML-элементы, чтобы модель могла определить правильный XPath;
- требования к формату 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 такой структуры:
| Поле | Описание |
|---|---|
| id | ID товара |
| sku | Артикул |
| name | Название |
| brand | Производитель |
| price | Цена |
| category_id | ID категории |
| 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(
'"',
replace($text, '"', '""'),
'"'
)
"/>
</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> </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> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Сохраняем результат в файл:
catalog-to-csv.xsl
Почему лучше давать ИИ именно XLS
Можно вручную перечислить поля в промпте:
id
sku
name
price
...
Но при большом количестве колонок XLS удобнее.
Во-первых, он уже является формальной спецификацией итогового файла.
Во-вторых, в нём могут находиться дополнительные данные:
название поля
описание
тип
обязательность
пример значения
комментарий
Например:
| field | description | required |
|---|---|---|
| product_id | Уникальный ID | yes |
| 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 под конкретную структуру фида.