«А у меня — Excel!»

Или как создать рабочий лист Excel из SAP PI без особых заморочек.

Попалась тут под руку задачка — одна из интегрируемых систем просит присылать данные поставщиков в формате листа Excel.
Формат простейший, что-то вроде такого:

Формат вроде несложный, но не «родной» для SAP PI. В практике приходилось работать с разными форматами, но в основном — с использованием Java в виде модулей адаптера или java-мэппинга.

В этот раз хотелось изящного, быстрого и дешевого решения, поэтому от просьбы «оценить задачу по-быстрому» пришлось уклониться и взять тайм-аут на подумать/потестировать. Запрос к мировому разуму дал несколько ссылок на решение, причем покрытое пылью времен 🙂 и давно существующее. 🙂

Нам на помощь пришел тот факт, что продукты Microsoft Office с некоторого времени перевели свои файлы в … XML-формат! То есть можно сделать соответствующий XML-документ, а Excel его считает как родной.

XML-формат документа Excel выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" 
xmlns:x="urn:schemas-microsoft-com:office:excel" 
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="https://www.w3.org/TR/html401/">
<Worksheet ss:Name="CognaLearn+Intedashboard">
<Table>
<Column ss:Index="1" ss:AutoFitWidth="0" ss:Width="110"/>
<Row>
<Cell><Data ss:Type="String">ID</Data></Cell>
<Cell><Data ss:Type="String">Project</Data></Cell>
<Cell><Data ss:Type="String">Reporter</Data></Cell>
<Cell><Data ss:Type="String">Assigned To</Data></Cell>
....

Перевод в такой формат может быть сделан любым инструментом меппинга — XSLT/Java/UDF.

Для создания такого файла я решил использовать простую промежуточную структуру XML с данными и XSLT-маппинг. В данном случае XSLT предпочтительней других инструментов, поскольку в целевом документе много пространств имен, а SAP PI в стандарте не умеет их добавлять штатными инструментами.
Исходником для данных может быть IDoc, Proxy, XML — эту часть задачи я сознательно не раскрываю. Но перед формированием excel ее нужно будет привести к удобному для xslt формату c помощью Message Mapping, например.
Структура данных для перевода в Excel простая (data type, message type), в ней есть строчки и столбцы с данными.

XSLT получился вот такой:

<?xml version="1.0" encoding="utf-8"?>
<?mso-application progid="Excel.Sheet"?>
<xsl:stylesheet version="1.0"
xmlns:html="http://www.w3.org/TR/REC-html40"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns="urn:schemas-microsoft-com:office:spreadsheet"
    xmlns:o="urn:schemas-microsoft-com:office:office" 
    xmlns:x="urn:schemas-microsoft-com:office:excel"
    xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">

<xsl:template match="/">
        <Workbook>
            <Styles>
                <Style ss:ID="Default" ss:Name="Normal">
                    <Alignment ss:Vertical="Bottom" />
                    <Borders />
                    <Font />
                    <Interior />
                    <NumberFormat />
                    <Protection />
                </Style>
                <Style ss:ID="s21">
                    <Font ss:Size="22" ss:Bold="1" />
                </Style>
                <Style ss:ID="s22">
                    <Font ss:Size="14" ss:Bold="1" />
                </Style>
                <Style ss:ID="s23">
                    <Font ss:Size="12" ss:Bold="1" />
                </Style>
                <Style ss:ID="s24">
                    <Font ss:Size="10" ss:Bold="1" />
                </Style>
            </Styles>

            <Worksheet ss:Name="CONTR">
                <Table>
                    <xsl:call-template name="CONTR_XML2XSL" />
                </Table>
            </Worksheet>
			<Worksheet ss:Name="USERS">
                <Table>
                    <xsl:call-template name="USERS_XML2XSL" />
                </Table>
           .........
        </Workbook>

    </xsl:template>

<xsl:template name="DISTR_XML2XSL">
        <Row>
                        <Cell>
                            <Data ss:Type="String">Код</Data>
                        </Cell>
                        <Cell>
                            <Data ss:Type="String">Название компании (краткое)</Data>
                        </Cell>
						<Cell>
                            <Data ss:Type="String">ИНН</Data>
                        </Cell>
						<Cell>
                            <Data ss:Type="String">КПП</Data>
                        </Cell>
						<Cell>
                            <Data ss:Type="String">Код контрагента</Data>
                        </Cell>
		.......
                    </Row>
        <xsl:for-each
            select="//CONTR">
            <Row>
                <Cell>
                    <Data ss:Type="String">
                        <xsl:value-of select="CODE" />
                    </Data>
                </Cell>
                <Cell>
                    <Data ss:Type="String">
                        <xsl:value-of select="NAME" />
                    </Data>
                </Cell>
				 <Cell>
                    <Data ss:Type="String">
                        <xsl:value-of select="INN" />
                    </Data>
                </Cell>
				 <Cell>
                    <Data ss:Type="String">
                        <xsl:value-of select="KPP" />
                    </Data>
                </Cell>
				.......
            </Row> 
        </xsl:for-each>
</xsl:template>
	
<xsl:template name="USERS_XML2XSL">
........
<xsl:template match="MT_Comp_Info">
</xsl:template>

</xsl:stylesheet>

Основные блоки преобразования здесь следующие:
<template match=»/»> соответствует корневому элементу исходного документа и первым «запускается» при преобразовании. Все, что содержится внутри этого тега — становится телом конечного xml-файла.
<xsl:call-template name=»CONTR_XML2XSL»> — вызывает соответствующий блок xslt — в нем уже идет перенос данных.
<data ss:type=»String»> — несет в себе содержимое ячеек, в виде обычного текста или тега <xsl:value-of select=»XYZ»> — для переноса данных из исходного XML

Далее делаем operation mapping с двумя шагами — преобразование из исходного IDoc/XML/Proxy (в случае прокси можно заменить этот шаг, заложив в прокси сразу формирование нужной структуры) в простую структуру, затем xslt — меппинг для получения XML в формате MIcrosoft Excel.

Конфигурируем интерфейс, используем файловый адаптер — и на выходе получаем искомый Excel-документ. И никакой Java в процессе. 🙂

Полезные ссылки:

Ваш Питрофф.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *