В SAP NetWeaver есть функционал для использования длинных текстов (более 100 символов и даже более 1000 ?). более технически корректное название sapscript text или, иногда, стандартные тексты.

Длинный текст может использоваться в качестве шаблонов в письмах, печатных формах, формировании договоров и любых других сущностей, где может быть «многабукав».

В одной из следующих статей мы детально разберем, как можно использовать шаблонизацию (это было пожелание одного из слушателей ABAP FIleOS) для писем на основе длинных текстов, а в этой статей покажем, как можно создать длинный текст с вложенными частями и как их прочитать в ABAP (по сути, базовые операции с сапскрипт).

Итак, пусть у нас имеется следующий текст, разделенный на логические части (а точнее 4 части).

Вводная часть текста, поясняющая про чего этот текст (например, тип договора и предмет договора; приветствие в письме и т.д.).

 Какой-то блок, который по форме одинаков для многих текстов, но отличается лишь некоторыми данными (например, участники договора купли-продажи; письмо, содержащее информацию о заказе/клиенте и т.д.)

 Поясняющая часть (которая может быть вообще разная для разных даже однотипных текстов).

 Завершающая часть в тексте, которая может повторяться для нескольких текстов.

Работа с составным длинным текстом (INCLUDE и копирование текстов)

Теперь я сделаю длинный текст в транзакции SO10, разбив текст также на 4 части. Для этого запускаю транзакцию SO10. Текст назову ZSD_MAIL_ORDER_CREATED_ALL.

Рис. 1 Создание текста в транзакции SO10
Рис. 1 Создание текста в транзакции SO10

Для наполнения содержим я буду использовать старый редактор (и, да я считаю его очень удобным для данных целей). Чтобы сменить/установить редактор используйте пункт меню Goto -> Change Editor/Configure Editor.

Рис. 2 Установка/смена редактора для ведения длинного текста
Рис. 2 Установка/смена редактора для ведения длинного текста

Для разделения текста на части я использую команду :/ (двоеточие и слэш) и укажу тексты, которые будут являться составными частями моего составного текста (самих текстов еще нет; я их сделаю следующим шагом также через транзакцию SO10).

Рис. 3 Составные части длинного текста, включенные с помощью INCLUDE
Рис. 3 Составные части длинного текста, включенные с помощью INCLUDE

Следующим шагом я создам каждый из указанных текстов через транзакцию SO10: ZSD_MAIL_ORDER_CREATED_01, ZSD_MAIL_ORDER_CREATED_02, ZSD_MAIL_ORDER_CREATED_03, ZSD_MAIL_ORDER_CREATED_04. На скриншотах ниже показано наполнение каждого из этих текстов.

Рис. 4 Длинный текст-include ZSD_MAIL_ORDER_CREATED_01
Рис. 4 Длинный текст-include ZSD_MAIL_ORDER_CREATED_01
Рис. 5 Длинный текст-include ZSD_MAIL_ORDER_CREATED_02
Рис. 5 Длинный текст-include ZSD_MAIL_ORDER_CREATED_02
Рис. 6  Длинный текст-include ZSD_MAIL_ORDER_CREATED_03
Рис. 6  Длинный текст-include ZSD_MAIL_ORDER_CREATED_03
Рис. 7 Длинный текст-include ZSD_MAIL_ORDER_CREATED_04
Рис. 7 Длинный текст-include ZSD_MAIL_ORDER_CREATED_04

В моем случае было удобно вводить текст простым вводом, однако полезно иметь ввиду функцию загрузки и выгрузки текста из файла, из другого текста и из буфера.

Для вставки текста из файла, меню: Text -> Upload/Download

Рис. 8 Загрузка/выгрузка текста из файла
Рис. 8 Загрузка/выгрузка текста из файла

Для загрузки текста из другого стандартного текста, меню: Insert -> Text -> Standard

Рис. 9 Вставка текста из другого ( или других) длинных текстов
Рис. 9 Вставка текста из другого ( или других) длинных текстов

Затем указываем параметры текста (можем вставить как ссылку на текст, так и его содержимое через галку «Expand Immediately»).

Рис. 10 Возможность вставки как содержимого текста так и ссылки на него
Рис. 10 Возможность вставки как содержимого текста так и ссылки на него

С помощью кнопки Выделить / F2, мы можем выделить строки текста и отправить его в буфер (в один из 5 буферов – то есть мы можем сделать за один раз сразу 5 выделений текста – ворду и не снилось…; относительно недавно с этим начала справляться windows и то только с помощью доп.ПО ? ).

Рис. 11 Кнопка Выделить в стандартном тексте для выделения строк в тексте и отправки их в буфер
Рис. 11 Кнопка Выделить в стандартном тексте для выделения строк в тексте и отправки их в буфер

После выделения нужных строк – они посинеют (цвет SAP). И их можно запомнить в буфере.

Рис. 12 Отправка строк текста в один из 5 буферов
Рис. 12 Отправка строк текста в один из 5 буферов

А затем (в другом тексте) мы можем извлечь скопированные строки из буфера

Рис. 13 Вставка скопированного текста из буфера
Рис. 13 Вставка скопированного текста из буфера

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

Рис. 14 Предпросмотр длинного текста (в том числе составного)
Рис. 14 Предпросмотр длинного текста (в том числе составного)

Видим, что система отображает именно содержимое вложенных текстов, а не INCLUDE с командами. И это полезно.

Рис. 15 Результат предпросмотра составного текста
Рис. 15 Результат предпросмотра составного текста

Чтение составных длинных текстов через ABAP

Итак, мы сделали составной текст, а также наполнили каждую часть содержимым. Как считать этот текст через ABAP/4 ?

Полный текст программы. Нам нужно 3 шага:

1)      Считаем длинные тексты при помощи функ.модуля READ_TEXT

2)      Заменим INCLUDE в составном тексте через функц.модуль TEXT_INCLUDE_REPLACE

3)      Затем заменим управляющие конструкции (если таковые есть) с помощью ФМа TEXT_CONTROL_REPLACE.

На экран выведем получившуюся строку через CL_ABAP_BROWSER.

    DATA ls_txt_head_in   TYPE thead.
    DATA ls_txt_head_out  TYPE thead.
    DATA lt_txt_lines     TYPE tline_tab.

    DATA lv_txt_full_str TYPE string.
    DATA lv_txt_full_html TYPE string.

    ls_txt_head_in-tdid     = p_tdid.
    ls_txt_head_in-tdspras  = p_langu.
    ls_txt_head_in-tdobject = p_tdobj.
    ls_txt_head_in-tdname   = p_tdname.

    _read_text_lines( EXPORTING is_txt_head = ls_txt_head_in
                      IMPORTING es_txt_head = ls_txt_head_out
                                et_txt_lines = lt_txt_lines ).
    CASE abap_true.

      WHEN do_html.
        _convert2html( EXPORTING is_txt_head  = ls_txt_head_out
                        CHANGING ct_txt_lines = lt_txt_lines
                                 cv_txt_str   = lv_txt_full_html ).

        _show_string( EXPORTING iv_str_show = lv_txt_full_html
                                iv_no_wrap  = abap_true ).

      WHEN OTHERS.

        _replace_include_n_controls( CHANGING cs_txt_head = ls_txt_head_out
                                      ct_txt_lines = lt_txt_lines ).

        _convert2string( CHANGING ct_txt_lines = lt_txt_lines
                                  cv_txt_str = lv_txt_full_str ).

        _show_string( lv_txt_full_str ).
    ENDCASE.
  METHOD _replace_include_n_controls.


    DATA lv_was_changed_replace TYPE abap_bool.
    DATA lv_was_changed_control TYPE abap_bool.

    IF ct_txt_lines IS INITIAL.
      RETURN.
    ENDIF.

    CALL FUNCTION 'TEXT_INCLUDE_REPLACE'
      EXPORTING

        header    = cs_txt_head          
      IMPORTING
        changed   = lv_was_changed_replace            
        newheader = cs_txt_head               
      TABLES
        lines     = ct_txt_lines.               


    CALL FUNCTION 'TEXT_CONTROL_REPLACE'
      EXPORTING
        header    = cs_txt_head             
      IMPORTING
        changed   = lv_was_changed_control          
        newheader = cs_txt_head               
      TABLES
        lines     = ct_txt_lines.              

  ENDMETHOD.

Также хотел бы обратить внимание на конвертацию длинного текста в формат HTML. Если HTML – это то, для чего Вы хотите использовать шаблон, то можете использовать ФМ CONVERT_ITF_TO_HTML. Подстановку и замену управляющих конструкций этот ФМ делает автоматически (при указании параметра ? )  (листинг3).

  METHOD _convert2html.
    "CHANGING ct_txt_lines TYPE tline_tab
    "         cv_txt_str   TYPE string.

    DATA lt_htmlline TYPE htmltable.
    FIELD-SYMBOLS <fs_html_line> TYPE htmlline.

    CLEAR cv_txt_str .

    CALL FUNCTION 'CONVERT_ITF_TO_HTML'
      EXPORTING
*       i_codepage     =                  " Target character set
        i_header       = is_txt_head                 " Text header of input text
*       i_page         = space            " Page specification for page window format
*       i_window       = space            " Window specification for page window format
*       i_syntax_check = space            " Activating the ITF syntax check
*       i_replace      = 'X'              " Expanding symbols and includes
*       i_print_commands   = space            " Outputting commands and text elements
*       i_html_header  = 'X'              " Output of the HTML header tag
*       i_funcname     = space            " Exit module for link interpretation
*       i_title        = space            " Title in HTML header
*       i_background   = space            " File name for HTML image as background
*       i_bgcolor      = space            " Background color of text
*       i_unescape_formats =                  " Exception Formats for Masking Special Characters
*       i_escape_spaces    = space            " Masking of Blank Characters
*       i_encoding     = space            " Define Character Set Coding in Header
*      IMPORTING
*       e_html_text    =                  " Text Content in HTML as Xstring
      TABLES
        t_itf_text     = ct_txt_lines                 " Text lines in ITF (input)
        t_html_text    = lt_htmlline                 " Text lines in HTML (output)
*       t_conv_charformats =                  " Table for character formats
*       t_conv_parformats  =                  " Table for paragraph formats
      EXCEPTIONS
        syntax_check   = 1                " Incorrect inout text ITF syntax
        replace        = 2                " Errors expanding includes and symbols
        illegal_header = 3                " Text header incorrect
        OTHERS         = 4.
    IF sy-subrc <> 0.
*     MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*       WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
    ENDIF.

    LOOP AT lt_htmlline ASSIGNING <fs_html_line>.
      IF cv_txt_str  IS INITIAL.
        cv_txt_str  = <fs_html_line>-tdline.
      ELSE.
        cv_txt_str  = cv_txt_str && <fs_html_line>-tdline.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.

Установка переменных

Конечно, никакие шаблоны не используются как статичные тексты. Одна из важных причин существования шаблонов (а в данном случае мы рассматриваем сапскрипт как шаблоны) – это возможность наполняться переменными данными. Давайте попробуем наполнить наш текст переменными. Переменные в текстах сапскрипт бывают трёх видов: системные, программные (класс, группа функций, исполняемая программа – это программы) и стандартные.

Давайте добавим в наш текст переменные. Синтаксис символов-переменных такой &SOME_VAR&. (подробнее тут). При использовании переменных полезно иметь ввиду опции форматирования: опции позволяют использовать нужный формат даты, времени; не выводить пустые переменные, добавлять пре- и пост- тексты к переменным и другие возможности (подробнее тут).

Добавим в текст ZSD_MAIL_ORDER_CREATED_02 переменные:

*

Какой-то блок, который по форме одинаков для многих текстов

*

, но отличается лишь некоторыми данными (например,

*

 участники договора купли-продажи; письмо, содержащее информацию

*

 о заказе/клиенте и т.д.)

*

                                                                       

*

Текущая дата: &DATE&

*

SYREPID: &SY-REPID&

*

                                                                       

*

Переменная из объекта:

*

S-V1:  &S-V1&

*

&'S-V2:  'S-V2&

/:

IF &S-V3& EQ 'СОЛОВЕЙ'.

*

 LLM-алгоритм говорит, что речь о птицах.

/:

ENDIF.

В данном тексте мы вывели дату через переменную &DATE& (она доступна в любом тексте); вывели имя отчета через &SY-REPID&, а также вывели значения переменных из той, программы, которая будет читать текст.

Переменная в тексте

Пояснение

&S-V1&

Выводит значение переменной S-V1.

То есть где-то в программе есть структура S (одна буква для краткости), а в ней есть поле V1.

Строка будет выведена в любом случае даже если переменная пустая

&'S-V2:  'S-V2&

В этом случае мы имеем пре-текст, то есть строчка не будет выведена, если переменная пустая

IF &S-V3& EQ 'СОЛОВЕЙ'.

А такие конструкции позволяет дорабатывать части шаблона с помощью проверки условий через IF.

Обратим внимание, что для замены именно переменных мы используем функциональный модуль: TEXT_SYMBOL_REPLACE. В качестве параметра передаем ему имя той программы (как правило, вызывающей, которая содержит переменные для шаблона).

REPORT zrep_c8a014_long_txt_symb.

TYPES: BEGIN OF ts_model
            , v1 TYPE string
            , v2 TYPE string
            , v3 TYPE string
            , v4 TYPE string
        , END OF ts_model
        .

PARAMETERS:   p_tdname TYPE thead-tdname DEFAULT 'ZSD_MAIL_ORDER_CREATED_ALL'
            , p_tdobj TYPE thead-tdid DEFAULT 'TEXT'
            , p_tdid TYPE thead-tdid DEFAULT 'ST'
            , p_langu TYPE sylangu DEFAULT 'RU'
            .

START-OF-SELECTION.
  DATA lv_txt TYPE string.
  DATA ls_txt_h TYPE thead.

  data s TYPE ts_model.

  ls_txt_h-tdid     = p_tdid.
  ls_txt_h-tdspras  = p_langu.
  ls_txt_h-tdobject = p_tdobj.
  ls_txt_h-tdname   = p_tdname.

  s-v1 = 'Переменная V1'.
  s-v2 = 'Вторая переменная'.
  s-v3 = 'СОЛОВЕЙ'.

  lv_txt = NEW zcl_c8a014_long_text( sy-cprog )->r( ls_txt_h ).

  DATA lv_as_html_out TYPE string.
  lv_as_html_out =
          | <html dir="ltr" lang="ru"> |
      && |<head> <meta charset="UTF-8">|
      && |<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">|
      && |<title>ABAP String Show </title>|
      && |</head> <body>|
      && |<div> { lv_txt } </div>|
      && |</body> </html>|
      .

  cl_abap_browser=>show_html(
    EXPORTING
      html_string  = lv_as_html_out                           " HTML String
).

Код класса ZCL_C8A014_LONG_TEXT доступен по ссылке. Текст программе в той же папке на github.

Таким образом, мы можем использовать длинные тексты в качестве шаблона.

Рис. 17 Результат использования шаблона с переменными
Рис. 17 Результат использования шаблона с переменными

Перенос текстов через транспортный запрос

Длинные тексты автоматически не вносятся в запрос. Однако в случае необходимости, их можно положить в запрос принудительно, сделав следующую запись в транспортном запросе.

R3TR      TEXT      TEXT, ZSD_MAIL_ORDER_CREATED_02,ST,R

Рис. 18 Запись добавленная вручную в транспортный запрос для переноса текста sapscript
Рис. 18 Запись добавленная вручную в транспортный запрос для переноса текста sapscript

В документации также, в качестве альтернативы ручному добавлению, обозначены две программы ( RSTXR3TR и RSTXSCRP) и рекомендация обратиться к справке.

Заключение

Сапскрипт-тексты можно использовать в качестве шаблонов. С их помощью можно сделать вложенный шаблон, наполнить его переменными и условными конструкциями. Однако, не стоит забывать про перенос текстов – автоматически тексты в запрос не добавляются. А также факт того, что сапскрипт-тексты хранятся в неструктурированном виде в рамках оперативной базы. В следующих статьях мы рассмотрим, как можно нарисовать «стилизованное письмо с картинками» на основе сапскрипта, а также альтернативы сапскрипту для ведения шаблонов.

Комментарии (0)