Простые трансформации

XML[1]Простые трансформации – язык программирования компании SAP позволяющий преобразовывать данные из ABAP в XML (Сериализация) и из XML в ABAP (Десериализация). Простые трансформации представляют из себя специальный вид программ, которые при желании можно отлаживать как обычные ABAP программы.

 

 

Запустить подобную программу можно с помощью ABAP оператора CALL TRANSFORMATION. Основные характеристики ST программ, в сравнении с XSLT:

  • Простота для понимания, за счёт декларативного описания.
  • Повышенная производительность, за счёт последовательного доступа к XML элементам.
  • Благодаря специальному синтаксису, используемому в данных программах, одна программа может быть использована как для сериализации, так и для десериализации.
  • Трансформация из одного набора данных ABAP в другой набор ABAP данных или из одного XML документа в другой не поддерживается, но возможна через два вызова трансформации.
  • Преобразование ссылочных переменных и объектов в настоящее время не поддерживается. Так же не поддерживается трансформация структур и таблиц, компонентами которых являются ссылочные переменные. Несмотря на это, допускается работа со ссылочными переменными (например, для вызова метода класса).

ST программы создаются либо через SE80, либо через транзакцию STRANS. ST программа должна представлять собой XML документ, со следующей структурой:

Первая строка <? … ?> используется для идентификации типа программы. Нет необходимости вводить её вручную, т.к. при проверке синтаксиса она будет введена автоматически.

Главный элемент ST программы tt:transform, в котором описаны пространства имен и главный шаблон. Элементы пространства имен «http://www.sap.com/transformation-templates» являются командами ST программы. Префикс пространства имен tt: используется для отображения команд из этого пространства. ST команды могут выступать в роли узлов XML документа или атрибутов в тестовых XML элементах (например при определении значения для текстового XML элемента).

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

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

Кроме того можно вставлять комментарии, т.к. ST программа это XML документ, комментарии определяются теми же правилами которые действуют для XML документа:

Имена в текстовых элементах зависят от регистра, т.о. <ELEMENT> и <element> два разных элемента.

Основная логика преобразования лежит внутри так называемых шаблонов, которые включают в себя набор ST команд. Когда вы определяете главный элемент tt:transform вы можете указать главный шаблон через атрибут template. Это первый шаблон, который выполнит ST программа при своем запуске. Если главный шаблон явно не определен, в ST программе должен присутствовать шаблон без имени, который будет запущен в роли главного. Шаблоны определяются командой tt:template.

Кроме определения главного шаблона и главного элемента, ST программы еще могут содержать следующие элементы:

  • Корневые узлы данных (Data Roots) определяющие связь между ABAP данными и ST программой (определяются командой tt:root);
  • Параметры, которые могут быть переданы через оператор CALL TRANSFORMATION (определяются командой tt:parameter);
  • Переменные (определяются командой tt:variable);
  • Типы данных, используемые в трансформации (определяются через оператор tt:type), заданные таким образом типы, можно использовать как в узлах данных, так и в параметрах и переменных;
  • Вложенные шаблоны, используемые в качестве разбиения логики ST программы на части.

Определение корневых узлов параметров и переменных

Определение корневых узлов

Для доступа к данным из ABAP программы, ST программа должна иметь хотя бы одно определение корневого узла. Корневые узлы представляют собой интерфейс по обмену данными из ST в ABAP программу и обратно, переменные из ABAP программы подставляются в параметрах source (сериализация) и result (десериализация) оператора CALL TRANSFORMATION.

Корневые узлы могут быть объявлены на уровне всей ST программы (tt:transformation) и на уровне вложенных шаблонов. Во вложенных шаблонах они не связаны с ABAP данными и используются для связи с корневыми узлами на верхнем уровне ST программы, при передаче через команду tt:with-root и объявляются в элементе tt:context (см. объявление вложенных шаблонов).

Синтаксис при объявлении корневых узлов следующий:

В качестве атрибута name указывается ABAP переменная, с которой необходимо связать узел, имя узла должно быть уникальным как среди других корневых узлов, так и среди объявленных в трансформации переменных (tt:variable) и параметров (tt:parameter). Имя не чувствительно к регистру.

Тип данных указывается через атрибут line-type или type. Line-type используется в случае указания на внутреннюю таблицу.  Если явно не указать тип данных, проверки сработают только во время выполнения трансформации, что в случае неверных данных может приводить к ошибкам:

  • К доступу несуществующего элемента структуры
  • Циклу не по табличной переменной
  • Обработки структуры как обычной переменной

В качестве типа могут быть указаны как элементарные ABAP типы, так и типы из словаря, и типы, объявленные через команду tt:type. При сериализации значения корневых узлов не могут быть изменены (например, через tt:assign) и доступны только для чтения, при десериализации только для записи (например, через tt:value).

Length – указывает на длину узла, Decimals на количество знаков после запятой, эти параметры указываются в случае необходимости для соответствующих им типов данных.

В приведенном ниже примере узел R1 объявлен с элементарным типом D, R2 – как таблица, состоящая из элементарного типа I, R3 — как структура, из ABAP словаря, R4 – Структура из пула типов, R5 – внутренняя таблица из структуры в классе cl_abc, R6 – структура с типом из трансформации. Обратите внимание на использование пространств имен.

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

Трансформация:

Создать трансформацию можно нажав правой кнопкой на пакете разработки, выбрав соответствующий пункт меню:

st_1

 

В появившемся диалоге выбрать тип трансформации (S – простая трансформация):

st_2

Результат работы программы:

st_3

Определение параметров

ST программы могут содержать параметры которые передаются в оператор CALL TRANSFORMATION и могут использоваться для определения логики поведения. Синтаксис их определения следующий:

Через атрибут name определяется имя параметра, которое не должно превышать 30 символов и должно быть уникально среди имен в корневых узлах, параметрах, переменных. Имя не чувствительно к регистру. Параметры определяются как на уровне главного шаблона, так и остальных используемых шаблонов, при этом параметры, определенные в одном шаблоне не могут быть доступны в другом.

Параметры могут быть использованы для вызова вложенных шаблонов (tt:apply) или других ST программ (tt:call), при указании атрибута with-parameter.

Атрибут kind определяет направление параметра, может принимать значения «in» — входящий, «out» — исходящий, «in/out» — входящий и исходящий. Если явно не задать направление, по умолчанию такой параметр будет входящим «in».

Параметры s-val, d-val, val – присваивают значение для параметра по умолчанию, могут быть выполнены следующие присвоения (приставки s- и d- тут и в других атрибутах указывают на процесс сериализации и десериализации):

Тип данных Представление
Floating point numbers (ABAP type f) F(‘value’)
Byte strings (ABAP types x and xstring) X(‘value’)
Date fields (ABAP type d) D(‘value’)
Decimal floating point numbers (ABAP types decfloat16, decfloat34) DECFLOAT16(‘value’)DECFLOAT34(‘value’)
Packed numbers (ABAP type p) P(value)
Integers (ABAP type i) I(value) | value
Numeric text fields (ABAP type n) N(‘value’)
Character strings (ABAP types c and string) C(‘value’) | ‘value’
Time fields (ABAP type t) T(‘value’)
Initial value (all ABAP types) initial

С помощью атрибута ref-type определяется атрибут, имеющий ссылочный тип, т.е. ссылка на глобальный ABAP класс или интерфейс, а так же на ссылочную переменную (REF TO DATA). При этом имена классов и интерфейсов указываются напрямую без указания пространства имен, а ссылочная переменная должна быть заранее определена через тип данных в команде tt:type, где нужно указать пространство имен. Параметры классов (интерфейсов) используются обычно для создания объектов или вызова методов, а ссылочные переменные как атрибуты в передаваемые методы. Получить значение параметра, можно используя команду tt:assign.

Примеры объявления параметров:

Как параметры при вызове других трансформаций:

Определение переменных

Переменные в ST программах объявляются командой tt:variable, которая имеет следующий синтаксис:

Атрибуты аналогичны описанным выше атрибутам для параметров. К переменным можно получать прямой доступ в шаблонах, но переменные, объявленные в одном шаблоне, не могут быть получены в другом. В случае необходимости их значения могут быть переданы при вызове шаблона.  В отличие от корневых узлов, переменные не связаны с ABAP данными. Для получения значения переменных используется команда tt:assign.

Определение типов

Корневые узлы, используемые в ST программах, могут, но не обязаны иметь присвоение типа. Обычно для этого используются типы из словаря или глобальных классов. Кроме того ST программы позволяют определять свои собственные типы данных, для этого служит команда: tt:type. Объявление типа происходит вне шаблонов ST программы. Команда tt:type имеет следующий синтаксис:

Атрибут name определяет имя типа. Вы можете определять как элементарные, структурные, так и табличные типы данных, которые могут быть частично или полностью родовыми. Кроме того возможна ссылка на ранее определенный локально в ST программе или глобальный тип данных через атрибут type.

При определении ссылки через атрибут [line-]type можно использовать следующие пространства имен:

  • http://www.sap.com/abapxml/types/dictionary если ссылаетесь на словарь.
  • http://www.sap.com/abapxml/types/type-pool/name если ссылаетесь на пул типов.
  • http://www.sap.com/abapxml/types/class-pool/class если ссылаетесь на глобальный атрибут класса.
  • http://www.sap.com/abapxml/types/defined/name если ссылаетесь на ранее определенный в текущей ST программе тип tt:type.

Имя типа необходимо указывать в верхнем регистре. Пример p:NAME, где p – определенное заранее, пространство имен.

Определение элементарных типов

При определении элементарного типа данных, атрибуту type должно быть присвоено одно из следующих значений: C, D, F, I, N, P, STRING, T, X или, XSTRING (в верхнем регистре).

Для типов C, N, P, X может быть указан атрибут length определяющий длину, а для типа P атрибут decimals указывающий на кол-во знаков после запятой. Если атрибут decimals указан без длинны, то он игнорируется. Если оба атрибута пропущены, их значения берутся как значения по умолчанию для родового типа.

Если для типа C не указать длину, это означает, что тип может иметь любую длину, как для string или csequence. Тоже самое справедливо и для типа X.

Определение структурных типов

Для определения структурных типов используется команда tt:node. Вложенная команда tt:node определяет элемент структуры с именем определенным в атрибуте name и типом type. Команда tt:node вложенная в другую команду tt:node определяет подструктуру. Элемент tt:type или tt:node,  который имеет вложенный элемент tt:node не должен иметь ссылку на тип в атрибуте type, вместо этого должно стоять значение «?». Порядок, в котором компоненты расположены в структуре, не имеет значения при связывании с ABAP структурой, кроме того некоторые поля могут отсутствовать в указании типа (см. атрибут extensible). Для определения порядка, в котором будут расположены компоненты структуры можно воспользоваться элементом tt:front, данный элемент может быть задан только в единственном числе для элементов tt:node и tt:type.

Для определения ограничений на тип структуры используется атрибут extensible. Может иметь следующие значения:

  • «on» — указывает на то, что текущий элемент может иметь вложенные элементы, явно не определенные в типе.
  • «deep» — указывает на то, что как текущий, так и его дочерние элементы могут иметь вложенные элементы, явно не определенные. Данное значение установлено по умолчанию.
  • «off» — текущий элемент не должен иметь других элементов, явно не описанных в типе.
  • «deep-off» — как текущий, так и его дочерние элементы не должны иметь элементы, явно не описанные в типе.

Определение табличных типов

Если для элемента tt:node или tt:type задан атрибут line-type, значит, данный элемент представляет собой внутреннюю таблицу с типом указанным в line-type. Если вы хотите объявить внутреннюю таблицу с указанным через команду tt:node структурным типом, для элемента верхнего уровня в качестве типа необходимо указать «?»:

Примеры объявления типов:

Определение ссылочных типов

Напрямую нельзя задать тип ссылки, но можно задать ссылку на ссылочную переменную из словаря. Например, на какой-нибудь класс, затем при объявлении параметров (переменных) указать на созданный тип со ссылкой на класс, после чего можно будет создать его и вызывать методы (см. ниже)

Адресация ABAP данных в ST программах

В ST программах все объекты данных представляют собой древовидную структуру.  Доступ к элементам (если они есть) в узлах осуществляется через точку. Каждый корневой узел данных (tt:root) имеет свою древовидную структуру. К данным можно обращаться либо указывая имя узла в ссылке, либо через текущий узел. Текущим узлом можно установить любой корневой узел, но текущим, в один момент времени, может быть только один узел.

Рассмотрим пример:

Трансформация:

Для того чтобы не указывать имя узла каждый раз, мы можем определить текущий узел. Для установки текущего узла можно воспользоваться командой tt:ref:

где name – имя узла. Приведенная выше трансформация может быть преобразована в следующий вид:

Для многих ST команд текущий узел может быть задан через атрибут ref. Пример:

Где instruction – имя ST команды. Кроме того текущий узел можно установить в ST атрибуте для текстового XML элемента, тогда наша трансформация будет иметь следующий вид:

Для текстовых элементов допускается указание значения через атрибут tt:value-ref, тогда трансформация примет следующий вид:

Если определен текущий узел, и доступ получаете через указание имени корневого элемента, необходимо указывать точку:

Кроме того во всех ST командах, которые позволяют явно задать текущий узел, к заданному узлу можно обратиться через константу $ref, при этом если текущий узел не задан, обращаться через $ref нельзя:

Существует следующее ограничение: если первый символ узла не является буквой или подчеркиванием или в имени встречаются символы кроме букв, чисел, дефисов и подчеркиваний, доступ к такому узлу необходимо получать с помощью оператора ref(‘ИмяУзла’).

Контроль выполнения сериализации и десериализации

Как было сказано выше, выполнение ST программы начинается с обработки главного шаблона программы. Внутри данного шаблона простой текст обрабатывается вместе с ST командами, после чего происходит либо сериализация, либо десериализация.

В процессе сериализации, текст введенный в ST программу переносится в создающийся XML документ без каких-либо изменений, выполняются ST команды, встречающиеся в этом тексте.

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

Определение текстового шаблона

В качестве текста шаблона могут быть представлены либо XML элементы с атрибутами, либо просто текст.

XML элементы и атрибуты определяются по обычным правилам построения XML документа, но не должны лежать в пространстве имен ST команд (без префикса tt:).  Используется следующий синтаксис:

Имя XML элемента может быть любым в рамках правил XML. Тут же могут быть статически прописаны атрибуты и их значения [attr].

Атрибут tt:ref устанавливает ссылку на текущий узел (см. выше).

Атрибут tt:lax определяет правило, по которому реагирует интерпретатор на несоответствие XML документа при десериализации относительно имён XML элементов и наличия атрибутов. Принимает следующие значения (по умолчанию deep-off):

  • «off» — XML атрибут во входящем потоке должен быть с тем же именем и наличием тех же атрибутов с такими же значениями что в программе.
  • «on» — XML элемент во входящем потоке может иметь любое имя, но при этом атрибуты и их содержимое должно совпадать.
  • «deep-on», «deep-off» — устанавливают те же правила, включая вложенные элементы.

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

Атрибут tt:extensible определяет правило, по которому реагирует интерпретатор на несоответствие вложенности и наличия других XML элементов, не описанных статически в ST программе. Может принимать следующие значения (По умолчанию «on»):

  • «on» — элемент XML может иметь вложенные элементы, явно не определенные в ST программе.
  • «deep-static» и «deep-dynamic» — текущий элемент и его вложенные элементы могут  иметь неопределенные вложенные элементы во входящем XML потоке.
  • «off» — запрещает расширение для текущего элемента, но не для его вложенных элементов.
  • «deep-off» — запрещает расширение для текущего элемента и его вложенных элементов.

Для всех вложенных элементов, значение атрибута может быть перезаписано. Разница между deep-static и deep-dynamic в том, что они имеют разные области действия. Deep-static используется только в текущем шаблоне, deep-dynamic выполняется для всех шаблонов и вызываемых ST программ.

Если необходимо задать атрибут для XML элемента динамически, делается это с помощью команды tt:attribute:

Где name – имя атрибута, ref – ссылка на текущий узел.  Значение передается командой tt:value, но можно так же использовать и короткую форму используя ST атрибут value-ref:

Вставка текста

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

…>text<…

Либо через ST команду:

…><tt:text>text</tt:text><…

В первом случае текст будет вставлен в документ XML, но проигнорирован в случае наличия в нем только пробелов. Во втором случае такой текст не игнорируется.

Сериализация: если текст не проигнорирован, все символы текста вставляются в создающийся XML документ, включая пробелы. Если текст был проигнорирован, ничего не попадает в XML.

Десериализация: Текст из XML потока посимвольно сравнивается с текстом из шаблона (включая пробелы и разрывы строк), если сравнение будет неудачным, система вызовет исключение CX_ST_MATCH_ELEMENT. Тексты могут быть пропущены командой tt:skip.

Трансформация ABAP данных

Для обработки ABAP данных служат следующие команды:

  • tt:value – для элементарных типов данных и компонентов структур.
  • tt:loop – для внутренних таблиц.
  • tt:copy – для работы с объектами данных целиком вместе с компонентами.

Обработка элементарных типов и компонентов структур

Для сериализации и десериализации элементарных типов данных используется команда tt:value:

Атрибут ref – определяет текущий узел. Узел должен быть элементарного типа, внутренние таблицы и структуры обрабатываются через команду tt:copy.   Элементарные типы отображаются в XML и обратно согласно заранее определенному asXML формату. Формат определяет соответствие элементарных типов ABAP и типов данных языка описания XML (XML schema). Следующая таблица показывает пример соответствия для этих преобразований (остальное можно найти в документации по asXML):

ABAP тип ABAP представление XML Scheme тип XML представление
b 123 xsd:unsignedByte 123
s -123 xsd:short -123
i -123 xsd:int -123
p -1.23 xsd:decimal -1.23
decfloat16 123E+1 precisionDecimal, totalDigits = 16 1.23E+3
decfloat34 -3.140…0E+02 precisionDecimal, totalDigits = 34 -314.0…0
f -3.140…0E+02 xsd:double -3.14E2

Кроме того для отдельных доменов из ABAP словаря существуют свои правила преобразования:

Домент ABAP представление XML Schema тип XML представление
XSDBOOLEAN «X», » « boolean «true», «false»
XSDDATE_D «20071001» date «2007-10-01»
XSDDATETIME_Z, XSDDATETIME_LONG_Z, XSDDATETIME_OFFSET, XSDDATETIME_LOCAL «20060727170334» dateTime «2006-07-27T17:03:34Z»
XSDLANGUAGE «E», «D» language «EN», «DE»
XSDQNAME «{URI}name» QName prefix:name
XSDTIME_T «115500» time «11:55:00»
XSDUUID_RAW, XSDUUID_CHAR «123456781234ABCDEF12123456789012» UUID «12345678-1234-abcd-ef12-123456789012

С помощью атрибута map можно задать правила для замены одного или нескольких значений другими. Правила задаются через запятую и с соблюдением следующего синтаксиса:

  • val(a1…an) > xml(x) – срабатывает при сериализации, указывает на то, что значения a1..an необходимо преобразовать в X.
  • xml(x1…xn) > val(a) – срабатывает при десериализации и указывает на то, что значения x1..xn необходимо преобразовать в A.
  • xml(x) = val(a) или val(a) = xml(x) – срабатывает как при сериализации так и при десериализации.

Пример, программа при сериализации заменяет все значения Woman и Man на Person:

С помощью атрибутов length, minLength, maxLength задается ограничение на длину значения при сериализации и десериализации.

В блоке validation для команд tt:value, tt:read и tt:write устанавливаются ограничения связанные с XML Schema типами и их сериализацией и десериализацией.

Указываются следующие атрибуты:

… xsd-type=»type»
[xsd-maxInclusive=»max»]
[xsd-maxExclusive =»max»]
[xsd-minInclusive=»min»]
[xsd-minExclusive =»min»]
[xsd-totalDigits=»dgts»]
[xsd-fractionDigits=»dgts»] …

Атрибут xsd-type указывает на тип данных XML Schema. Значение для сериализации и десериализации должно входить в диапазон указанного типа, в противном случае система вызовет исключение CX_ST_SERIALIZATION_ERROR при сериализации и CX_ST_DESERIALIZATION_ERROR при десериализации.

Кроме указания типа задаются следующие атрибуты:

  • xsd-maxInclusive – максимально допустимое значение, включая указанное, xsd-maxExclusive – максимально допустимое число не включая указанное.
  • xsd-minInclusive – минимально допустимое число, включая указанное, xsd-minExclusive – минимально допустимое число не включая указанное.
  • xsd-totalDigits, fractionDigits – максимальное кол-во число цифр до и после запятой.

Пример трансформации:

Программа вызова:

В данном примере допустимо только преобразования чисел в диапазоне от 30000 до 32767 (предел типа Short).

Ограничение на длину значений

Вы можете использовать атрибуты minLength, maxLength и length для определения длинны в таких командах как: tt:value, tt:read, tt:write. Параметры определяют ограничения на значения, передаваемые при сериализации и десериализации.

В качестве значения может быть передано положительное целое число. Данные атрибуты можно задать для узлов данных или переменных с типами: с, x, string и xstring. Для всех остальных типов данные ограничения игнорируются.

Сериализация: атрибуты length или minLength определяют количество символов или байт (x), которые будут переданы в итоговый XML документ. Если будет передано значение с меньшей реальной длинной, недостающие до length символы будут заполнены справа либо пробелами, либо нулевым байтом (в зависимости от типа). Атрибуты length или maxLength определяют максимально возможное число символов или байт, которые могут быть переданы в XML документ. Если будет передано больше символов, возникнет исключение CX_SY_CONVERSION_DATA_LOSS (если только оставшиеся символы не состоят из пробелов или нулевых байтов).

Десериализация: атрибут minLength игнорируется, атрибуты length и maxLength задают максимальное число символов или байтов, которое ожидается для получения из XML документа. Если оно содержит большее количество символов и эти символы не являются пробелами и  нулевыми байтами, система вызовет исключение CX_ST_CONSTRAINT_ERROR. Причем данное исключение не может быть обработано при вызове CALL TRANSFORMATION.

Обработка таблиц

Сериализация и десериализация внутренних таблиц  происходит в цикле, где на каждой итерации текущим узлом задается строка таблицы. Для обработки таблиц служит команда tt:loop:

Атрибут ref – как и в других командах, указывает на узел данных, который содержит внутреннюю таблицу, name – задает псевдоним для доступа к текущей строке внутренней таблицы.

Пример трансформации с обработкой внутренней таблицы:

Программа:

Возвращаемый XML:

Комплексная обработка ABAP данных

С помощью команды tt:copy можно провести сериализацию и десериализацию для всех типов данных, кроме ссылочных переменных. Данная команда запускает XSL трансформацию и преобразует данные в формат asXML (аналогично стандартной трансформации ID). Так, например, мы можем вывести целиком всю структуру без указания всех её компонентов, либо внутреннюю таблицу, если нам не нужно дополнительной обработки этих компонентов. Пример трансформации к предыдущей программе:

Результатом обработки будет следующий XML:

Присвоение значений

Вы можете использовать команду tt:assign для присвоения значений узлам данных, параметрам и переменным. Команда имеет следующий синтаксис:

Атрибуты to-ref и to-var указывают куда передать значение, ref, val и var – какое значение передавать. В качестве полей источников и полей назначения могут выступать:

  • Узлы данных (ref), следует помнить, что их содержимое не может быть изменено при сериализации и считано во время десериализации. Нельзя записать из одного узла в другой.
  • Переменные и параметры (var).
  • Так же можно передавать значения напрямую (константы) через атрибут val.

В случае необходимости можно использовать команду по преобразованию типов tt:cast. Для работы с внутренними таблицами можно использовать следующий синтаксис:

В данном случае в таблицу itab добавляется новая строка и компоненту comp присваивается значение.

Для очистки значений переменных, узлов данных и параметров служит команда tt:clear:

Где можно указать либо имя узла через атрибут ref, либо переменную или параметр через атрибут var.

Сериализация: во время сериализации установка значений может быть выполнена только для параметров и переменных, если в качестве назначения указан узел данных или неявно текущий узел, данное присвоение игнорируется.

Десериализация: во время десериализации в качестве источника данных могут выступать только переменные (параметры) и значения, если указать в качестве источника ссылку на узел данных, данное присвоение будет проигнорировано.

Вывод значений переменных (параметров)

Во время сериализации можно вывести значения переменных и параметров в XML документ, делается это с помощью команды tt:write:

Где var – имя переменной или параметра, map – список с правилами замены (см. выше), Length, minLength – ограничения вывода по длине.

Пример использования команды:

Результат: <X>333</X>. При десериализации данная команда игнорируется.

Чтение значений XML элементов

Во время выполнения десериализации с помощью команды tt:read можно получить значение XML атрибута, синтаксис команды следующий:

Атрибут variable – указывает на имя переменной или параметра, куда необходимо записать считанное значение. Length, maxLength – ограничение по длине, в данном случае обозначают одно и тоже. Decimals – кол-во знаков после запятой, map – список правил присвоения. Type – тип данных. Команда поддерживает считывание только родовых типов.

Пример использования команды:

Если входной XML будет таким: <X>333</X>, узлу ROOT будет назначено значение 333. Данная команда игнорируется при сериализации.

Управление ходом выполнения

Определение направления

С помощью команд <tt:serialize> и <tt:deserialize> можно определить, какие команды будут выполнены при сериализации, а какие при десериализации. Синтаксис следующий:

Пример трансформации:

Пропуск элементов при десериализации

В том случае, когда необходимо пропустить тот или иной элемент XML документа можно воспользоваться командой tt:skip:

При десериализации данная команда имеет следующий эффект:

  • Если не заданы атрибуты, пропускается текущий элемент в XML потоке.
  • Если атрибуты установлены, пропускается элемент с именем name, пропуск будет cnt раз, при этом, если значение будет равным «*», элемент будет полностью проигнорирован при десериализации.
  • Если имя не установлено, будет пропущено cnt следующих элементов.

Пример трансформации:

Программа:

Условные трансформации

Позволяют отделить набор ST команд и выполнить их только при определенных условиях. Используются как отдельно, так и внутри таких команд как tt:switch и tt:group. Синтаксис выглядит следующим образом:

Префикс s- и d- используются тогда, когда условия должны обрабатываться только для сериализации или только для десериализации. Префикс –var используется если условная трансформация применяется относительно переменных или параметров.

Определение предусловий

Атрибут using определяет предусловия, могут быть следующими:

Предусловие Обозначение
exist() Срабатывает когда указанный узел существует
type-C() Срабатывает если узел типа C
type-D() Срабатывает если узел типа D
type-F() Срабатывает если узел типа F
type-I() Срабатывает если узел типа I
type-N() Срабатывает если узел типа N
type-P() Срабатывает если узел типа P
type-T() Срабатывает если узел типа T
type-X() Срабатывает если узел типа X

Пример:

Указанное условие можно записать следующим образом: «type-C(ROOT)».  Через запятую можно указывать несколько условий:

Определение утверждений

Оператор data определяет утверждения, если утверждение истинно выполняется блок ST команд. В противном случае вызывается исключение CX_ST_COND_CHECK_FAIL. В утверждениях могут быть использованы как узлы данных, так и переменные и просто значения:

  • Узлы данных, как и во всех других условиях, записываются в форме ref(‘ИмяУзла’), либо просто ИмяУзла.
  • Переменные и параметры var(ИмяПеременной)

Утверждения бывают двух видов:

  • Сравнение со значением по умолчанию — initial(..)
  • Сравнение со значением: ref(‘ИмяУзла’) = 22

В следующем примере, если значение ROOT1 не будет равно ABC, система вызовет исключение:

Определение проверок

Атрибут check позволяет задавать условия относительно значений переменных, параметров и узлов данных. Приставка –var (var-check) в данном атрибуте используется для условий относительно переменных и параметров.

Через условия можно определить состояние значений в переменных, параметрах, узлах:

  • exist(‘ИмяУзла’) – выполняется, если указанный узел существует.
  • Initial(ref(‘ИмяУзла’) или ИмяПеременной) – выполняется если узел или переменная (параметр) имеют пустое значение
  • Not-initial(..) – противоположность initial.

Пример:

В атрибуте check так же можно задавать условия сравнения синтаксис следующий:

Ref(‘ИмяУзла’)|var(ИмяПеременной)|Значение Оператор Ref(‘ИмяУзла’)|var(ИмяПеременной)|Значение

Существуют следующие операторы:

Оператор Значение
= Условие выполняется, если оба операнда равны
!= Условие выполняется, если значения операндов не равны
>, &gt; Значение выполняется если значение левого операнда больше правого
>=, &gt;= Значение выполняется если значение левого операнда больше или равно правого
&lt; Значение выполняется если правый операнд больше
&lt;= Значение выполняется если правый операнд меньше или равен левому

Как видно из таблицы, оператор < в XML всегда должен быть заменен &lt; Оператор > может быть заменен на &gt; но можно и не менять.

Пример использования:

Условия в атрибуте check можно объединять через оператор and или or, так же доступны скобки и отрицание, через оператор not. Пример:

Если содержимое tt:[s-|d-]cond не является шаблоном, должен быть указан хотя бы один атрибут: check, data, using.

Определение шаблона

Когда условная трансформация десериализуется, содержимое шаблона, находящееся между <tt:cond> .. </tt:cond> используется как критерий присвоения.  Шаблон содержит одну или несколько конструкций используемых как маркеры. Наиболее распространенная форма маркера – текстовый XML элемент, если содержимое шаблона состоит из одного XML элемента, с тем же именем что и обрабатываемый элемент из XML потока, то условие считается положительным и XML элемент обрабатывается. Если в шаблоне несколько маркеров, то условие обрабатывается, если все маркеры были обработаны.

Допустим, имеем следующий XML документ:

Трансформация, использующаяся при десериализации:

Шаблон обработается успешно, если во входящем потоке будут последовательно найдены элемент Z и элемент X, если их порядок в шаблоне будет другим, шаблон не выполнится, и будут пропущены эти два элемента, обработается только Y.

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

Шаблоном можно назвать условия, содержимое которых содержит:

  • Обычный текст в виде XML элементов и статических атрибутов
  • Динамические атрибуты, объявленные в команде tt:attribute
  • Текст, если он не пустой
  • Явно определенный пустой шаблон, через команду tt:empty, может быть использован, если не известно есть ли внутри узла компоненты.

Если в предыдущую программу передать следующий XML:

Её обработка вызовет ошибку, но если добавить в неё пустой шаблон, ошибки не произойдет:

Порядок обработки условных трансформаций при сериализации:

  • Предварительные условия
  • Утверждения
  • Условия сравнения

Блок условий обрабатывается, когда все три проверки возвращают истинное значение.

Порядок обработки условных трансформаций при десериализации:

1. Является ли содержимое условной трансформации шаблоном

1.1. Если содержимое является шаблоном, сравниваются последовательно элементы в XML потоке. Если шаблон не выполняется, условная трансформация пропускается, при этом элементы из XML потока не пропускается из обработки. Если шаблон корректен, переходим к шагу 2.

1.2. Если не шаблон переходим к шагу 2.

2. Проверка предусловий

2.1. Если содержимое является шаблоном и предусловие не выполняется, команда tt:cond пропускается, при этом элементы во входящем XML потоке пропускаются (не десериализуются). Если предусловие выполняется, переходим к шагу 3.

2.2. Если содержимое не является шаблоном и предусловие не выполняется, при десериализации срабатывает исключение CX_ST_REF_ACCESS. Если предусловие выполняется, переходим к шагу 3.

3. Выполнение инструкций внутри условной трансформации. На данном этапе происходит десериализация узлов данных, их существование можно было проверить на шаге 2. Результат десериализации можно будет проверить на шаге 5.

4. Установка утверждений. Если в момент десериализации значение в утверждении не совпадет со значением в XML потоке, система вызовет исключение CX_ST_COND_CHECK_FAIL.

5. Проверка условий. Если условия не выполняются, десериализация будет прервана с исключением CX_ST_COND_CHECK_FAIL.

Использование команды выбора

Аналогично оператору CASE в ABAP, в ST программах может использоваться команда выбора, позволяющая от определенных условий выполнять те или иные ST команды или обработать шаблон, синтаксис данной команды:

Префикс var применяется, когда команда выбора применяется относительно переменной или параметра.

В отличие от условных трансформаций, используемых вне оператора tt:case, tt:group, нет необходимости в объявлении хотя-бы одного из атрибутов using,check,data, если содержимое условных трансформаций не шаблон.

При использовании команд выбора необходимо помнить следующее:

  • Вы можете определить только одно условие стандартное для сериализации (s-), т.е. то где не заполнены атрибуты check,using, data.
  • Вы можете определить только одно стандартное условие десериализации (d-), т.е. то, что не содержит шаблон.

Шаги, выполняемые при сериализации:

  1. Первое релевантное для сериализации условие выбора tt:[s-]cond, выбранное относительно условий в using, data, check обрабатывается, далее происходит выход из команды tt:switch.
  2. Если подобного условия не было найдено, обрабатывается условие выбора без атрибутов с проверками (без data, check, using – стандартное условие сериализации, если такое условие выбора есть), далее выход из команды tt:switch.
  3. Если ни одно из условий не было обработано система вызовет исключение CX_ST_SWITCH_NO_CASE.

Шаги, выполняемые при десериализации:

  1. Сначала ищется первое подходящее условие выбора tt:[d-]cond с подходящим шаблоном и условиями, заданными через атрибуты. Если найдено подходящее, произойдет выход из команды tt:switch.
  2. Если система не нашла подходящего условия выбора, обрабатывается стандартное условие для десериализации, если такое существует. Если при этом условия определенные через атрибуты для стандартного условия выбора не выполняются, система выдает исключение CX_ST_REF_ACCESS.
  3. Если система не смогла найти подходящего условия выбора, она выдаст исключение  CX_ST_SWITCH_NO_CASE.

Следующий пример демонстрирует работу с командой switch, при сериализации числовые значения заменяются на текстовые, при десериализации текстовые заменяются числовыми:

Тот же пример без использования префиксов, но с указанием направления для команды выбора:

Использование группировок

В том случае, когда не известно сколько раз, тот или иной элемент в XML документе будет повторяться и в какой последовательности, можно воспользоваться группировками.

Следующий пример демонстрирует такой случай:

Для удобства обработки такой последовательности, используются группировки:

Как и для команды tt:switch условные трансформации можно создавать для конкретного направления ([s-|d-]cond). Но нельзя внутри них использовать вложенные условные трансформации с другим типом направления.

В отличие от условных трансформаций, используемых вне оператора tt:case, tt:group, нет необходимости в объявлении хотя-бы одного из атрибутов using,check,data, если содержимое условных трансформаций не шаблон.

Для контроля того, как часто относительно десериализации условная трансформация может быть выполнена, заполняется параметр frq (frequency- частота):

  • 1 – должна быть обработана 1 раз.
  • ? – может быть обработана, а может и нет.
  • * — может быть обработана ноль и более раз.

Сериализация: во время сериализации элемент tt:group выполняется один раз: все зависимые относительно сериализации условные трансформации с предустановленными условиями или без них выполняются в указанном порядке.

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

  1. Выбирается первая условная трансформация с подходящим шаблоном
  2. Если такая не обнаружена, система пытается выполнить стандартную для десериализации условную трансформацию, не содержащую шаблона. Если для неё не будут выполнены ограничения: using, check, data система выдаст исключение CX_ST_REF_ACCESS.
  3. Если система не может выполнить обязательных условных трансформаций, вызывается исключение CX_ST_GROUP_MISSING_CASE.

Рассмотрим приме, имеется следующая трансформация:

Допустим, XML будет следующим:

Тогда система выполнит следующие действия:

  1. В первой итерации цикла система пытается десериализовать элемент X1, узлу ROOT присваивается значение 1.
  2. Во второй итерации система обрабатывает второй элемент X1, т.к. для данной условной трансформации указана частота 0 и более, узлу ROOT будет назначено новое значение 2.
  3. Далее система десериализует элемент X2, для условной трансформации с подходящим шаблоном этого элемента, частота установлена хотя бы 1 раз, что значит, что она будет выполнена на этой итерации и узлу  ROOT2 будет передано значение 4.
  4. На четвертой итерации система вновь обрабатывает элемент X2, но т.к. условная трансформация для него уже была выбрана ранее, система запускает стандартную для десериализации условную трансформацию, в которой вызывается команда для пропуска элемента tt:skip.
  5. На пятой итерации система обрабатывает условную трансформацию с элементом X3, т.к. частота для неё не задана, по умолчанию равна 1 и она является последней обязательной условной трансформацией, цикл на этом завершается.
  6. Шестой элемент из XML потока обрабатывается уже вне конструкции группировки tt:group

Модульное построение ST программ

В ST программах возможно разбиение логики на отдельные части, путем определения и вызова вложенных шаблонов. Все шаблоны в ST программе, за исключением главного являются вложенными.

Определение вложенных шаблонов

Вложенные шаблоны определяются следующим способом:

Атрибут name определяет уникальное имя для вложенного шаблона, имя не должно быть пустым и не должно совпадать с главным шаблоном или другими вложенными шаблонами.

Во вложенных шаблонах через команду tt:context можно объявлять свои узлы данных, параметры и переменные. Узлы данных во вложенных шаблонах не имеют прямой связи с ABAP данными, они используются (как и параметры) в роли интерфейса между шаблонами, т.е. мы можем, запуская вложенный шаблон, передать в значения его узлов данные из узлов запускающего шаблона через команду tt:with-root.  В значения параметров так же передаются значения из вызывающих шаблонов. Переменные (tt:variable) используются для внутренних целей шаблона и не изменяются через вызывающий шаблон, доступ к ним может иметь только шаблон, внутри которого они определены.

Вызов вложенных шаблонов

Для вызова вложенных шаблонов используется команда tt:apply:

Атрибут name задает имя вложенного шаблона, ref- текущий узел, для передачи данных во внутренние узлы данных используется команда tt:with-root, для передачи в параметры команда tt:with-parameter.

Пример трансформации с использованием вложенного шаблона:

Программа для её вызова:

Результат:

Использование других ST программ

В ST программах есть возможность вызова других ST программ и включение содержимого одной ST программы в другую.

Вызов ST программ

Для вызова программ необходимо воспользоваться командой tt:call:

Атрибут transformation задает имя ST программы, как и при вызове вложенных шаблонов ST программу можно вызвать, передав в неё узлы данных и параметры (описание см. выше).

Включение содержимого программ

Для включения содержимого одной программы в другую необходимо воспользоваться командой tt:include, со следующим синтаксисом:

Данная команда не может быть вызвана внутри шаблона, по умолчанию она копирует все именованные вложенные шаблоны (пропуская шаблоны без имени). Необходимо убедиться в том, что не будет дублирования имен шаблонов. Через атрибут templates можно напрямую задать, какие вложенные шаблоны необходимо скопировать.

Доступ к ABAP объектам из ST программ

В ST программах можно использовать объекты и классы из ABAP’а следующим образом:

  • Вызывать статические методы объекта
  • Вызывать методы инстанции объекта
  • Создавать объекты
  • В методах так же можно получать доступ к XML потоку

Вызов методов

Для вызова метода необходимо воспользоваться командой tt:call-method:

Если вызывается статический метод, в атрибуте class указывается имя класса, в котором этот метод находится, если метод инстанции, то в атрибут var передается имя переменной или параметра, ссылочного типа, которая указывает на объект, атрибут ref-type переменной или параметра должен быть явно указан. Атрибут name указывает на имя метода, а префиксы в случае необходимости можно использовать для разграничения направления трансформации.

С помощью элементов tt:with-paramteter задаются параметры, передающиеся в метод класса. Атрибут name указывает на имя параметра, префиксы s- и d- указывают на направление трансформации. В качестве значения может быть передана ссылка на узел данных (ref), параметр или переменная (var) или значение (val).

Не стоит забывать, что при сериализации узлы будут доступны только для чтения, а при десериализации только для записи.

Тип передаваемого в метод параметра должен совпадать с типом в интерфейсе метода. Типом узла данных, в котором явно не указана ссылка на тип, будет тип ABAP переменной связанной с этим узлом. Параметры и переменные, не имеющие явного указания на тип через атрибут ref-type, определяются как ссылочные переменные.

Когда выполняется ABAP метод, управление из ST обработчика переходит к ABAP обработчику. Нет никаких ограничений на конструкции, используемые в методе, если выполняются операторы ENDMETHOD и RETURN управление возвращается назад к ST обработчику, однако возврат может быть не осуществлен если:

  • Если будут запущены операторы LEAVE PROGRAM, SUBMIT без дополнений AND RETURN, LEAVE TO TRANSACTION.
  • Метод вызвал исключение объектное исключение, тогда ST программа вызовет свое исключение CX_ST_CALL_METHOD_ERROR, в котором в качестве атрибута EXCEPTION_NAME будет передано имя оригинального класса исключения.
  • Если будет вызвано не объектное исключение, ST обработчик вызовет не отлавливаемое исключение.

Если к узлам данных привязаны данные, которые изменяются вызовом метода, эти изменения немедленно отображаются на узлах данных. Но существуют следующие ограничения: в ST команде tt:loop нельзя изменить данные таблицы, которые обрабатываются в цикле.

В атрибуты reader и writer передается имя атрибута, в вызываемом методе, который является ссылочным типом, со ссылкой на интерфейс IF_SXML_WRITER или IF_SXML_READER. В момент вызова метода, в него передается ссылочная переменная на объект, реализующий данный интерфейс, через который можно получить доступ к XML потоку. Объект создается каждый раз при вызове метода. В зависимости от объявления имени метода и его направления можно указать только writer, если метод запущен для сериализации и только reader, если метод запущен для десериализации. Если метод запускается для обоих направлений, можно указать как reader, так и writer.

Пример вызова статического метода в сериализации:

Программа, вызывающая трансформацию:

Создание объектов

При вызове методов инстанции ABAP объектов, необходимо чтобы эти объекты существовали. Если в качестве ссылочной переменной, при вызове метода, указана ST переменная, необходимо чтобы объект был создан (Параметр с объектом может быть создан вне ST программы). Для создания объектов необходимо воспользоваться командой tt:create-object:

Атрибут var – содержит имя переменной или параметра со ссылочной переменной, указывающей на ABAP класс или интерфейс. Атрибут class определяет имя создаваемого класса:

  • Если var – переменная со ссылкой на класс, атрибут class должен содержать имя этого класса или имя класса его наследника.
  • Если var – переменная со ссылкой на интерфейс, атрибут class должен содержать имя класса, его реализующего.

Через элементы tt:with-parameter передаются параметры в конструктор класса. Исключения, создаваемые внутри класса и правила передачи параметров те же, что и для вызова методов.

Ссылки по теме: справка от SAP.

11 комментариев

  1. Хорошая штука… наверно, для тех у кого много проектов связанных с xml… ежедневно
    а вот тем кто сталкивается с тем чтоб как-то манипулировать с xml-ем раз пол в года, не факт

    Вот представил, сейчас я с эти разберусь, сделаю проект, через пол года потребуется что то исправит … и мне опять придётся изучать эту штуку заново

  2. SAP в принципе система сложная, с кучей всевозможных API для разработчиков, не говоря уже о разных UI, функциональных особенностях относительно модулей и т.п. Главное чтобы была возможность быстро вспомнить как ту или иную технологию использовать, помнить её и держать в голове будет наверное лишним, да и невозможно все держать в голове. Но в качестве средства манипулирования XML,ST возможно будет проще ООП реализации парсеров XML.

  3. Скажите, пожалуйста, Михаил, я правильно понимаю что за счет последовательного доступа у простых трансформаций порядок параметров в тексте xml (для которого написана трасформация) не должен меняться? И соответственно, если поменять местами два параметра в xml-тексте, то придется переделывать трансформацию?

  4. Видимо между строками:

    Допустим, XML будет следующим:

    Тогда система выполнит следующие действия:

    Пропущен скриншот c XML, вдруг будет полезно.
    Отличная статья, спасибо.

  5. Автор очень скромен, и думает, что все такие же умные как и он сам. По сути статья помогает разработчикам найти ответы на возникающие у них вопросы. Для функционального консультанта — темный лес. Автор зачем то использует свою терминологию, не удосуживаясь вопросами определения терминов. Для примеров выбрана спорная стратегия, в которой имена тегов такие же как имена элементов структур. В результате не статья, а каша. Возможно, тем кто работал с трансформациями достаточно плотно, она и будет полезна, для остальных, ее прочтение имеет ту же пользу, что и изучение документации от SAP

    1. Привет Vlad! К большому сожалению автор статью не сможет Вам ответь, Можно много кого критиковать но автора данного блога сделал много.
      Жаль что такие люди уходят

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

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