Меню

Создание 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. Но, к счастью, такие требования к формам не слишком часты.

Примечание. 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 (Телефон)
  • EMAIL  

После этого активируем созданную структуру.

Рис.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 синей линией:

  1. Выделим в дереве Структуры формуляра узел с цветной клеткой (так обозначается компонент Паттерн).
  2. Затем, в Excel-шаблоне выделим диапазон ячеек A1:G7.
  3. Затем, во вкладке "Свойства компонента", в пункте "Область в шаблоне" нажмем кнопку с карандашом (Рис.9):

Рис.9. Связь Паттерна с шаблоном установлена

В результате этих трех несложных действий компонент Паттерн оказался связан с выделенной областью шаблона.

Заменим наименование и описание Паттерна на более понятное (Рис.10):

Рис.10. Смена наименования и описания Паттерна

Теперь выполним связь с шаблоном для оставшихся трех компонентов: FULLNAME, PHONE и EMAIL. Этот тип компонентов называется Значением и служит для передачи данных из одного поля контекста в одну ячейку Excel-формы. Принцип связывания этих компонентов с шаблоном точно такой же, как и для Паттерна (Рис.9) .

4.2.5. Активация формуляра

Активируем формуляр нажатием кнопки со "спичкой".

4.3. Программа печати

Программа печати включает в себя три этапа:

  1. Объявление контекста
  2. Заполнение контекста
  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

Спасибо за статью. А как с разрывами страниц для печати в данной технологии? Можно ли ими управлять без VBA?

Комментарий от  

Игорь Бородин

  |  13 сентября 2016, 15:47

Спасибо за статью. А как с разрывами страниц для печати в данной технологии? Можно ли ими управлять без VBA?

Без VBA можно вставлять принудительные разрывы страниц. Иногда этого бывает достаточно. Контролировать же автоматические разрывы можно только через VBA/OLE. Однако, эта функция уже встроена в XLSX Workbench и вам не придется писать макросы. Об этой функции сказано здесь: sites.google.com/site/sapxlwb

Комментарий от  

бабкен минасян

  |  20 сентября 2016, 00:35

Прекрасная статья! Автор проявил академический подход к извечной проблеме создания отчетности в формате MS Excel. Конкретные и наглядные примеры. Впрочем, все возможности его разработки раскрыты здесь: sites.google.com/site/sapxlwb

Комментарий от  

Игорь Бородин

  |  21 ноября 2016, 15:30

Вышла новая версия 4.00 . В ней появилась возможность вставки своего макроса VBScript - для реализации особых требований, для которых недостаточно основного функционала.
Подробнее сказано здесь: sites.google.com/site/sapxlwb

Комментарий от  

Алексей Еськин

  |  21 августа 2022, 11:56

Игорь, добрый день.
1)Если упрощенно, то надо создать динамическое количество однотипных таблиц, на листе, чтобы они были друг под другом.  В них будут отличаться только названия колонок, незначительно. Например, мы заранее определили что будет 3 итерации, надо вывести 3 таблицы, друг под другом, где каждая таблица будет иметь два столбца например, дата и сумма. В каждой итерации, название столбца "дата" меняется на "дата + 1" те "дата1"..."датаN". Запуск не в диалоге, так что макросы нельзя.
В общем это как цикл внутри цикла. Такое возможно сделать?
2) Как окрашивать строку по условию. Например есть строка  с подитогами, в контексте мы будем иметь флаг, подитогов. Это делается через условное форматирование? Как мне использовать в условиях значение из контекста, если оно нигде не выводится(этот флаг).

Комментарий от  

Алексей Еськин

  |  21 августа 2022, 18:37

Игорь, добрый день.
1)Если упрощенно, то надо создать динамическое количество однотипных таблиц, на листе, чтобы они были друг под другом.  В них будут отличаться только названия колонок, незначительно. Например, мы заранее определили что будет 3 итерации, надо вывести 3 таблицы, друг под другом, где каждая таблица будет иметь два столбца например, дата и сумма. В каждой итерации, название столбца "дата" меняется на "дата + 1" те "дата1"..."датаN". Запуск не в диалоге, так что макросы нельзя.
В общем это как цикл внутри цикла. Такое возможно сделать?
2) Как окрашивать строку по условию. Например есть строка  с подитогами, в контексте мы будем иметь флаг, подитогов. Это делается через условное форматирование? Как мне использовать в условиях значение из контекста, если оно нигде не выводится(этот флаг).

1)Удалось сделать через "патерны"+появление при наличии значения в поле

Комментарий от  

Алексей Еськин

  |  22 августа 2022, 09:09

Игорь, добрый день.
1)Если упрощенно, то надо создать динамическое количество однотипных таблиц, на листе, чтобы они были друг под другом.  В них будут отличаться только названия колонок, незначительно. Например, мы заранее определили что будет 3 итерации, надо вывести 3 таблицы, друг под другом, где каждая таблица будет иметь два столбца например, дата и сумма. В каждой итерации, название столбца "дата" меняется на "дата + 1" те "дата1"..."датаN". Запуск не в диалоге, так что макросы нельзя.
В общем это как цикл внутри цикла. Такое возможно сделать?
2) Как окрашивать строку по условию. Например есть строка  с подитогами, в контексте мы будем иметь флаг, подитогов. Это делается через условное форматирование? Как мне использовать в условиях значение из контекста, если оно нигде не выводится(этот флаг).

2) Удалось сделать через вывод скрытого столбца+условное форматирование