Создание Excel-форм в XLSX Workbench
1. Аннотация
Автор дает краткий обзор существующих методов создания печатных форм в Excel-совместимых форматах, а также знакомит читателя с инструментом XLSX Workbench посредством серии «пошаговых» примеров: от простого к сложному. Примеры демонстрируют реализацию элементов типовых печатных форм: Табличная часть, Изображение, Диаграмма, Иерархическая структура (дерево).
2. Введение
С выгрузкой данных в MS Excel-совместимый формат рано или поздно сталкивается каждый ABAP-разработчик, так как данный формат не теряет своей популярности у пользователей, и они довольно часто предпочитают Excel другим средствам - SmartForms и AdobeForms. На тему реализации Excel-форм уже накопилось огромное количество информации и наработок, и для каждой типовой задачи можно найти массу решений. Однако, у этого есть и обратная сторона - разнообразие способов реализации одной и той же задачи не способствует поддержанию порядка в этой части разработок и, как следствие, усложняет их сопровождение. Не претендуя на полноту списка, я изложу лишь наиболее часто встречаемые мной на проектах подходы к форматированной выгрузке данных в Excel.
Примечание. Инструмент SmartForms пришел на смену морально устаревшему SapScript, обладая гораздо более дружественным графическим интерфейсом и позволяя обходиться без программирования в 90% случаев. Ссылка по теме.
Примечание. Официальное название PDF-Based Print Forms считается более продвинутым и современным инструментом для создания форм, чем SmartForms. Является составной частью более крупного решения SAP Interactive Forms by Adobe. Ссылка по теме.
Как правило, выгрузка основывается на файле-шаблоне, хранимом в WEB-репозитарии и содержащем базовое форматирование результирующей формы. В тексте шаблона имеются особые метки, которые в runtime заменяются на значения, передаваемые из программы печати. Другие размеченные области шаблона могут дублироваться, удаляться и претерпевать изменения согласно логике, имплементированной в программе печати или в макросе VBA. Использование файла-шаблона позволяет, в случае необходимости, легко вносить изменения в формат отдельных ячеек и областей.
Технологии выгрузки:
-
Формирование файла исключительно средствами DOI / OLE / VBA в различных сочетаниях.
Традиционный стандартный набор низкоуровневых API Desktop office integration (DOI) позволяет сделать многое, а в сочетании с VBA - практически всё (разумеется, в рамках возможностей MS Excel). Но напрямую в программах печати эти API используется довольно редко. Чаще на их основе разрабатываются более удобные пользовательские решения для выгрузки форм. Передача данных из программы печати в целевые ячейки шаблона может быть реализована следующими способами (но не только ими):- Передача значений из программы печати непосредственно в целевые ячейки шаблона средствами DOI / OLE.
- Передача внутренних таблиц в шаблон средствами DOI в виде коллекции таблиц и последующий их разбор и форматирование VBA-макросом.
- Выгрузка внутренней таблицы в промежуточный CSV (или какой-либо другой) файл с последующей загрузкой его в шаблон, разбором и форматированием VBA-макросом. Как уже было сказано, главный плюс использования DOI / OLE / VBA - в абсолютной гибкости форматирования. Минусы же следующие:
- Требуются разрешения на запуск макросов (если используются).
- Невозможность работы в фоновом режиме.
- Загрузка локальной машины пользователя. Длительное формирование "тяжелого" файла (или большого числа файлов) может существенно замедлить или вовсе парализовать остальную работу пользователя.
-
Сборка файла в открытых форматах на стороне сервера приложений .
- Сборка файла в формате "Таблица XML 2003" (XMLSS). Технически этот формат представляет собой единый XML-файл, описывающий содержимое книги Excel. До появления формата "Open XML", формат "Таблица XML 2003" был единственной возможностью получения Excel-совместимой формы в фоновом режиме. Собственно, в этом заключается его главный плюс. Минусы же данного формата в том, что файл на выходе получается довольно "тяжелый" по сравнению с XLS или XLSX, а также, не поддерживает многие опции форматирования (такие как условное форматирование, диаграммы, рисунки и др.). Чаще всего такой файл получают посредством XSLT-трансформации (которая, кроме прочего, выполняет функцию шаблона). В этом случае, я бы дополнительным плюсом назвал использование только штатных средств (т.е. без использования различных Z-утилит). А дополнительным минусом - довольно кропотливый труд при внесении даже небольших изменений в исходное форматирование.
-
Сборка файла в формате "Open XML" (XLSX, XLSM). Технически этот формат представляет собой ZIP-архив, содержащий несколько XML-файлов, описывающих различные составляющие книги Excel. Кроме того, что данный формат современнее, чем XLS, существует возможность формирования его прямо на сервере приложений, без участия приложения MS Excel. Возможные средства реализации:
- Стандартные классы CL_XLSX_* находятся в пакете S_OOXML_XLSX. Как и DOI, они представляют собой низкоуровневые API, которые в исходном виде использовать непосредственно в программе печати весьма трудоемко (к тому же для их использования необходимо иметь базовые представления о спецификации формата Open XML). Таким образом, к этим API сама собой напрашивается пользовательская "обертка" для более комфортной работы.
- Хорошо известная пользовательская разработка западных коллег - набор классов для работы с XLSX и XLSM файлами. Данная разработка проще в использовании, чем, CL_XLSX_* , а также, поддерживает VBA-макросы (в случае с XLSM-файлом), что существенно расширяет её функциональность. Справедливости ради, стоит сказать, что иногда невозможно обойтись без постобработки файла средствами DOI / OLE / VBA. Дело в том, что некоторые вещи (такие как: контроль автоматических разрывов страниц; вставка итоговых строк по каждой печатной странице; настройка оптимальной высоты/ширины для объединенных ячеек; и др.) умеет делать только приложение MS Excel. Но, к счастью, такие требования к формам не слишком часты.
- Стандартные классы CL_XLSX_* находятся в пакете S_OOXML_XLSX. Как и DOI, они представляют собой низкоуровневые API, которые в исходном виде использовать непосредственно в программе печати весьма трудоемко (к тому же для их использования необходимо иметь базовые представления о спецификации формата Open XML). Таким образом, к этим API сама собой напрашивается пользовательская "обертка" для более комфортной работы.
Примечание. Desktop Office Integration (DOI) - набор ABAP-интерфейсов, позволяющих установить взаимодействие между ABAP-программой и офисными приложениями, установленными на локальной машине пользователя, посредством OLE2-интерфейса. Ссылка по теме.
Примечание. Формат XML Spreadsheet (XMLSS) описывает основное содержимое и форматирование книги. Однако, следующие функции не поддерживаются: Диаграммы, OLE-объекты, Рисунки и автофигуры, VBA-проекты, Группировка строк/столбцов. Ссылка по теме.
Примечание. Формат Office Open XML (так же известный как Open XML или OOXML) предназначен для большинства офисных документов (электронные таблицы, текст, презентации и т.д.) был изначально разработан Microsoft. Файл представляет собой ZIP-архив, содержащий некоторое количество XML-файлов ("parts"). Также в ZIP-архиве могут содержаться медиафайлы, например, растровые изображения и др. Ссылка по теме.
Перечисленные подходы, в разной степени удобства использования, решают вопрос экспорта данных в Excel-формат. Но отчего их такое множество? И почему такого "разброда и шатания" не наблюдается для SmartForms или AdobeForms? По большей части не потому ли, что (вместо API-полуфабрикатов) для них изначально созданы удобные и самодостаточные среды разработки, позволяющие визуально конструировать структуру формы и настраивать все её опции? Этот риторический вопрос сподвиг меня к разработке визуального конструктора Excel-форм XLSX Workbench, с которым я и хотел бы вас познакомить в настоящей статье. Главное отличие XLSX Workbench от имеющихся на сегодняшний день решений в простоте и наглядности процесса разработки формы - знать ABAP и VBA при этом не обязательно, всё делается с помощью кликов мышью. Этот инструмент с легкостью позволяет создавать как простые, так и очень сложные (в том числе и полностью динамические) формы. В качестве дополнительного бонуса - возможность получения формы в фоновом режиме.
Примечание. XLSX Workbench - бесплатный и находящийся в открытом доступе инструмент для создания печатных форм в формате OpenXML (XLSX). Официальный сайт проекта.
Приведенные ниже (разделы 4-9) примеры базируются на стандартных таблицах из модели данных для обучения SAP Flight Model.
Примечание. Flight model - это набор объектов ABAP-словаря (таблиц, структур, типов) и программных компонентов, имеющих логическую взаимосвязь. Являются основой для многих стандартных обучающих примеров. Ссылка по теме.
3. Основные понятия в XLSX Workbench
Рис.1. Модель
Контекст служит для передачи данных между Программы печати и Формой (Рис.1). Контекстом может быть любая структура, табличный тип и даже элемент данных. Главное условие - это должен быть тип, объявленный в словаре данных. Проще говоря - заходим в SE11 и создаем табличный тип или структуру (либо берем уже имеющуюся) - это и будет контекст.
Программа печати (Рис.1). нужна только для того, чтобы заполнить данными контекст и вызвать Ф.М. ZXLWB_CALLFORM, передавая ему на вход этот контекст.
Форма (Рис.1). создается и редактируется в транзакции ZXLWB_WORKBENCH. Процесс разработки формы повторяет многие принципы разработки в SmartForms. Например, за основу взято представление структуры формуляра в виде иерархии компонентов. Форматирование итогового документа определяется сочетанием отдельных фрагментов шаблона (компонент "Паттерн"), а за передачу текста в ячейку документа отвечает компонент "Значение", который связан с Контекстом. Существуют и другие компоненты ("Цикл", "Папка" и др.), с помощью которых возможно реализовать почти любое требование по форматированию.
4. Создание простейшей формы. Вывод полей: Исполнитель/ Телефон/ E-mail.
4.1. Контекст
В качестве контекста будем использовать структуру, объявленную в словаре данных. Зайдем в транзакцию SE11 и создадим структуру (тип данных) с наименованием ZXLWB_EXAMPLE1_CONTEXT (Рис.2). В структуру добавим три поля - все они имеют тип STRING:
- FULLNAME (Исполнитель)
- PHONE (Телефон)
После этого активируем созданную структуру.
Рис.2. Создание структуры
4.2. Формуляр
4.2.1. Создание и сохранение формуляра
Запустим транзакцию ZXLWB_WORKBENCH и создадим форму с наименованием, например, EXAMPLE1 (Рис.3):
Рис.3. Создадание формы
Сразу же после создания сохраним формуляр, нажав на кнопку с дискеткой и указав требуемый пакет для сохранения (Рис.4):
Рис.4. Сохранение формуляра
4.2.2. Разметка шаблона
В Excel-шаблоне, находящемся в правой части экрана, нарисуем следующее (Рис.5):
Рис.5. Разметка шаблона
4.2.3. Присвоение контекста формуляру
Для привязки контекста к формуляру необходимо выделить корневой узел Структуры формуляра и на вкладке "Свойства формуляра", в пункте "Наименование контекста" нажать кнопку с карандашом. На открывшемся popup-экране укажем ZXLWB_EXAMPLE1_CONTEXT . На предложение "создать структуру формуляра автоматически" отвечаем утвердительно, как показано на Рис.6:
Рис.6. Присвоение контекста и автоматическое создание структуры формуляра
В результате, будет автоматически создана такая структура, как показана на Рис.7:
Рис.7. Структура формуляра
4.2.4. Связь компонентов структуры формуляра с Excel-шаблоном
Теперь нам необходимо установить связь узлов дерева Структуры формуляра с областями Excel-шаблона. Схема связи представлена на Рис.8:
Рис.8. Схема связи компонентов с шаблоном
Сначала выполним связь, обозначенную на Рис.8 синей линией:
- Выделим в дереве Структуры формуляра узел с цветной клеткой (так обозначается компонент Паттерн).
- Затем, в Excel-шаблоне выделим диапазон ячеек A1:G7.
- Затем, во вкладке "Свойства компонента", в пункте "Область в шаблоне" нажмем кнопку с карандашом (Рис.9):
Рис.9. Связь Паттерна с шаблоном установлена
В результате этих трех несложных действий компонент Паттерн оказался связан с выделенной областью шаблона.
Заменим наименование и описание Паттерна на более понятное (Рис.10):
Рис.10. Смена наименования и описания Паттерна
Теперь выполним связь с шаблоном для оставшихся трех компонентов: FULLNAME, PHONE и EMAIL. Этот тип компонентов называется Значением и служит для передачи данных из одного поля контекста в одну ячейку Excel-формы. Принцип связывания этих компонентов с шаблоном точно такой же, как и для Паттерна (Рис.9) .
4.2.5. Активация формуляра
Активируем формуляр нажатием кнопки со "спичкой".
4.3. Программа печати
Программа печати включает в себя три этапа:
- Объявление контекста
- Заполнение контекста
- Вызов Ф.М.'ZXLWB_CALLFORM'
Создадим отчет (тип 1-Выполняемая программа) с наименованием, например, ZXLWB_EXAMPLE1 и вставим в него этот код (не забыв активировать) :
REPORT zxlwb_example1.
* объявили контекст
DATA gs_context TYPE zxlwb_example1_context .
* заполнили контекст
PERFORM fill_context .
* отобразили форму
*Вызов
CALL FUNCTION 'ZXLWB_CALLFORM'
EXPORTING
iv_formname = 'EXAMPLE1'
iv_context_ref = gs_context
EXCEPTIONS
OTHERS = 2.
IF sy-subrc NE 0 .
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF .
*&---------------------------------------------------------------------*
*& Form fill_context
*&---------------------------------------------------------------------*
* Заполнение контекста
*----------------------------------------------------------------------*
FORM fill_context .
*=======================================================================
* 1) Исполнитель/ Телефон/ E-mail
*=======================================================================
DATA:
ls_address TYPE bapiaddr3 ,
lt_return TYPE STANDARD TABLE OF bapiret2 .
CALL FUNCTION 'BAPI_USER_GET_DETAIL'
EXPORTING
username = sy-uname
IMPORTING
address = ls_address
TABLES
return = lt_return.
CONCATENATE ls_address-fullname '(' sy-uname ')'
INTO gs_context-fullname " -->> Исполнитель
SEPARATED BY space .
gs_context-phone = ls_address-tel1_numbr . " -->> Телефон
gs_context-email = ls_address-e_mail . " -->> E-mail
ENDFORM . "fill_context
4.4. Проверка результата
Запустим нашу программу печати ZXLWB_EXAMPLE1 (например, нажатием клавиши F8). Если мы всё сделали правильно, то увидим результат, показанный на Рис.11:
Рис.11. Печать отчёта
5. Вывод таблицы Авиакомпаний
5.1. Контекст
Добавим в наш контекст поле TABCARR с табличным типом TY_SCARR. Таким образом, мы добавили в контекст вложенную таблицу (Рис.12):
Рис.12. Добавление в контекст вложенной таблицы TABCARR
5.2. Формуляр
После того, как мы добавили новое поле в контекст, необходимо перезапустить транзакцию ZXLWB_WORKBENCH, для актуализации контекста в форме.
5.2.1. Разметка шаблона
Добавим в шаблон «серую строку» (Рис.13) под той областью, что мы разметили ранее.
Рис.13. Добавление «серой» строки в шаблон
5.2.2. Добавление компонента Цикл
Добавим Цикл ниже Паттерна (на одном уровне с ним). Для этого, выделим в дереве структуры вышестоящий узел SHEET и нажмем на кнопку "Создать компонент". Из появившегося списка выберем компонент Цикл. На следующем экране укажем его название и описание. После этого созданный компонент Цикл отобразится в дереве структуры (Рис.14)
Рис.14. Добавление компонента Цикл в дерево структуры
Теперь свяжем Цикл с таблицей TABCARR из контекста. Для этого во вкладке "Свойства компонента", в пункте "Связь с контекстом" нажмем кнопку с карандашом и в popup-списке выберем TABCARR (Рис.15):
Рис.15. Связываем Цикл с таблицей контекста
5.2.3. Добавление компонента Паттерн для строки таблицы.
Выделив узел Цикла в дереве структуры, нажмем кнопку "Создать компонент". Из появившегося списка выберем Паттерн и укажем его название и описание. После этого, созданный компонент Паттерн отобразится в дереве структуры (Рис.16):
Рис.16. Добавление компонента Паттерн для строки таблицы в дерево структуры
Свяжем добавленный Паттерн с областью в Excel-шаблоне. Для этого сначала выделим узел Паттерна в дереве, затем, выделим в шаблоне ячейки A8:G8, и после этого, во вкладке "Свойства компонента" в пункте "Область в шаблоне" нажмем на кнопку с карандашом. Связь с шаблоном установлена.
5.2.4. Добавление Значений для строки таблицы.
Выделив узел Паттерна строки в дереве структуры, нажмем кнопку "Создать компонент". В появившемся списке, дважды щелкнем на изображении точки с тремя стрелочками - так включается режим создания Значений путем выбора полей из контекста. В появившемся списке дважды щелкнем по полям CARRNAME и CURRCODE - слева них появится зеленая галочка. Нажмем кнопку "Создать" внизу списка, после этого созданные Значения отобразится в дереве структуры (и они уже будут иметь связь с контекстом), как это показано на Рис.17:
Рис.17. Добавление Значений в дерево структуры
Теперь остается только сопоставить созданные Значения с целевыми ячейками шаблона по схеме, показанной на Рис.18:
Рис.18. Схема связи Значений с целевыми ячейками шаблона
Для этого выделим узел компонента в дереве структуры, затем выделим целевую ячейку шаблона, после этого, во вкладке "Свойства компонента" в пункте "Область в шаблоне" нажмем кнопку с карандашом. Связь с шаблоном установлена.
5.2.5. Активация формуляра
Активируем формуляр нажатием кнопки со "спичкой".
5.3. Программа печати
Вставим в подпрограмму FILL_CONTEXT новые строчки кода (ниже заполнения полей Исполнитель/ Телефон/ E-mail):
*=======================================================================
* 2) Таблица авиакомпаний
*=======================================================================
SELECT *
INTO TABLE gs_context-tabcarr[]
FROM scarr .
5.4. Проверка результата
Запустим нашу программу печати ZXLWB_EXAMPLE1 и увидим такой результат, как на Рис.19:
Рис.19. Печать отчёта
6. Вывод футера с логотипом
Под таблицей выведем нижнюю часть формы, называемую футером, или "подвалом". В футер поместим картинку (логотип), которая будет загружаться в формуляр прямо из WEB-репозитария. Мы можем её видеть в транзакции SMW0 (Рис.20):
Рис.20. Объект логотипа в WEB-репозитарии
6.1. Контекст
Добавим в контекст новое поле LOGO с типом RAWSTRING (Рис.21):
Рис.21. Добавление поля в контекст
6.2. Формуляр
Перезапустим транзакцию ZXLWB_WORKBENCH, для актуализации контекста в форме.
6.2.1. Разметка шаблона
Добавим прямоугольную область, внутри которой будет располагаться логотип. Он будет занимать несколько объединенных ячеек в правом нижнем углу этой области (Рис.22):
Рис.22. Локализация логотипа в форме
6.2.2. Добавление компонентов Паттерна и Рисунка
Добавим Паттерн ниже Цикла (на одном уровне с ним). Для этого, выделим в дереве структуры вышестоящий узел SHEET и нажмем на кнопку "Создать компонент". Из появившегося списка выберем компонент Паттерн. На следующем экране укажем его название и описание. После этого созданный компонент Паттерн отобразится в дереве структуры (Рис.23):
Рис.23. Паттерн в дереве структуры
Для созданного Паттерна FOOTER создадим дочерний узел Рисунок. Выделим узел Паттерна в структуре формуляра и нажмем на кнопку "Создать компонент". Из появившегося списка выберем компонент Рисунок. На следующем экране укажем его название и описание. После этого созданный компонент отобразится в дереве структуры (Рис.24):
Рис.24. Рисунок в дереве структууры
Теперь необходимо сопоставить созданные Паттерн и Рисунок с областями шаблона по схеме, показанной на Рис.25:
Рис.25. Схема связи компонентов с шаблоном
Для этого выделим узел компонента в дереве структуры, затем выделим целевую область шаблона, после этого, во вкладке "Свойства компонента" в пункте "Область в шаблоне" нажмем кнопку с карандашом. Связь с шаблоном установлена.
Для компонента Рисунок дополнительно необходимо установить связь с
Если хотите прочитать статью полностью и оставить свои комментарии присоединяйтесь к sapland
ЗарегистрироватьсяУ вас уже есть учетная запись?
Войти
Обсуждения 7
Комментарий от
Александр Тустановский
| 13 сентября 2016, 15:05
Комментарий от
Игорь Бородин
| 13 сентября 2016, 15:47
Александр Тустановский 13 сентября 2016, 15:05
Спасибо за статью. А как с разрывами страниц для печати в данной технологии? Можно ли ими управлять без VBA?
Комментарий от
бабкен минасян
| 20 сентября 2016, 00:35
Комментарий от
Игорь Бородин
| 21 ноября 2016, 15:30
Подробнее сказано здесь: sites.google.com/site/sapxlwb
Комментарий от
Алексей Еськин
| 21 августа 2022, 11:56
1)Если упрощенно, то надо создать динамическое количество однотипных таблиц, на листе, чтобы они были друг под другом. В них будут отличаться только названия колонок, незначительно. Например, мы заранее определили что будет 3 итерации, надо вывести 3 таблицы, друг под другом, где каждая таблица будет иметь два столбца например, дата и сумма. В каждой итерации, название столбца "дата" меняется на "дата + 1" те "дата1"..."датаN". Запуск не в диалоге, так что макросы нельзя.
В общем это как цикл внутри цикла. Такое возможно сделать?
2) Как окрашивать строку по условию. Например есть строка с подитогами, в контексте мы будем иметь флаг, подитогов. Это делается через условное форматирование? Как мне использовать в условиях значение из контекста, если оно нигде не выводится(этот флаг).
Комментарий от
Алексей Еськин
| 21 августа 2022, 18:37
Алексей Еськин 21 августа 2022, 11:56
Игорь, добрый день.
1)Если упрощенно, то надо создать динамическое количество однотипных таблиц, на листе, чтобы они были друг под другом. В них будут отличаться только названия колонок, незначительно. Например, мы заранее определили что будет 3 итерации, надо вывести 3 таблицы, друг под другом, где каждая таблица будет иметь два столбца например, дата и сумма. В каждой итерации, название столбца "дата" меняется на "дата + 1" те "дата1"..."датаN". Запуск не в диалоге, так что макросы нельзя.
В общем это как цикл внутри цикла. Такое возможно сделать?
2) Как окрашивать строку по условию. Например есть строка с подитогами, в контексте мы будем иметь флаг, подитогов. Это делается через условное форматирование? Как мне использовать в условиях значение из контекста, если оно нигде не выводится(этот флаг).
Комментарий от
Алексей Еськин
| 22 августа 2022, 09:09
Алексей Еськин 21 августа 2022, 11:56
Игорь, добрый день.
1)Если упрощенно, то надо создать динамическое количество однотипных таблиц, на листе, чтобы они были друг под другом. В них будут отличаться только названия колонок, незначительно. Например, мы заранее определили что будет 3 итерации, надо вывести 3 таблицы, друг под другом, где каждая таблица будет иметь два столбца например, дата и сумма. В каждой итерации, название столбца "дата" меняется на "дата + 1" те "дата1"..."датаN". Запуск не в диалоге, так что макросы нельзя.
В общем это как цикл внутри цикла. Такое возможно сделать?
2) Как окрашивать строку по условию. Например есть строка с подитогами, в контексте мы будем иметь флаг, подитогов. Это делается через условное форматирование? Как мне использовать в условиях значение из контекста, если оно нигде не выводится(этот флаг).