Десериализация JSON xstring в структуру в ABAP - PullRequest
1 голос
/ 26 февраля 2020

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

TYPES: BEGIN OF json_subobject,
         c TYPE i,
         d TYPE decfloat34,
       END OF json_subobject.
TYPES: BEGIN OF json_object,
        a TYPE c LENGTH 10,
        b TYPE json_subobject,
       END OF json_object.

DATA: foo TYPE json_object.

Я моделирую эту структуру в JSON следующим образом:

{
  "a":"FooBar",
  "b":{
    "c":9,
    "d":3.14
  }
}

Сейчас Я написал простую программу для проверки оператора CALL TRANSFORMATION на приведенном выше JSON в сочетании с приведенными выше определениями структуры. Программа должна десериализовать JSON (жестко запрограммированный в переменной lv_xmls) и распечатать содержимое полученной структуры. Содержимое структуры должно соответствовать содержимому оригинала JSON. Это программа:

TYPES: BEGIN OF json_subobject,
         c TYPE i,
         d TYPE decfloat34,
       END OF json_subobject.
TYPES: BEGIN OF json_object,
         a TYPE c LENGTH 10,
         b TYPE json_subobject,
       END OF json_object.

DATA: foo TYPE json_object.

DATA: lv_xmls TYPE string VALUE '{"a":"FooBar","b":{"c":9,"d":3.14}}',
      lv_xmlb TYPE xstring.

TRY.
    lv_xmlb = cl_abap_codepage=>convert_to(
                source      = lv_xmls
                codepage    = `UTF-8`
                endian      = space
                replacement = '#'
                ignore_cerr = abap_false ).
  CATCH cx_parameter_invalid_range cx_sy_codepage_converter_init cx_sy_conversion_codepage cx_parameter_invalid_type.
    ENDTRY.

WRITE: |Deserializing JSON ...|.
NEW-LINE.

CALL TRANSFORMATION id SOURCE XML lv_xmlb RESULT XML = foo.

WRITE: '{'.
NEW-LINE.
WRITE: |  "a": "{ foo-a }",|.
NEW-LINE.
WRITE: |  "b": \{|.
NEW-LINE.
WRITE: |    "c": { foo-b-c },|.
NEW-LINE.
WRITE: |    "d": { foo-b-d },|.
NEW-LINE.
WRITE: |  \}|.
NEW-LINE.
WRITE: |\}|.

Вывод, который я ожидал бы получить:

Deserializing JSON ...
{
  "a":"FooBar",
  "b":{
    "c":9,
    "d":3.14
  }
}

Но, к сожалению, вывод, который я получаю:

Deserializing JSON ...
{
  "a":"",
  "b":{
    "c":0,
    "d":0
  }
}

Это выглядит например, оператор CALL TRANSFORMATION ничего не делает для меня.

Есть ли гуру ABAP, который мог бы показать мне, как использовать CALL TRANSFORMATION в этом (надеемся) простом случае? Я уже осмотрелся и обнаружил это полезное репозиторий GitHub , демонстрирующий, как десериализовать JSON в класс, но я бы предпочел десериализовать JSON в структуру для простоты. Я не совсем уверен, как использовать CALL TRANSFORMATION, потому что я незнаком с XSLT и продвинутыми XML функциями, поэтому я был бы очень признателен за готовое решение, если это возможно ...

Большое спасибо заранее

Джошуа

Ответы [ 2 ]

4 голосов
/ 26 февраля 2020

Мой ответ состоит из двух частей. Первое, на мой взгляд, лучше всего подходит для JSON, а вторая часть объясняет, почему ваш код не работает с CALL TRANSFORMATION ID.

ЧАСТЬ 1:

You лучше использовать один из классов SAP, который лучше подходит для обработки JSON. Я предпочитаю класс /UI2/CL_JSON, который, на мой взгляд, является самым «открытым» классом, потому что он наиболее популярен в SAP (см. Документацию ниже), хотя официально не поддерживается (да, это трудно понять, добро пожаловать в мир SAP) .

TYPES: BEGIN OF json_subobject,
         c TYPE i,
         d TYPE decfloat34,
       END OF json_subobject.
TYPES: BEGIN OF json_object,
         a TYPE c LENGTH 10,
         b TYPE json_subobject,
       END OF json_object.

DATA: foo TYPE json_object.

/ui2/cl_json=>deserialize(
    EXPORTING json = '{"a":"FooBar","b":{"c":9,"d":3.14}}'
    CHANGING  data = foo ).

ASSERT foo = VALUE json_object( 
    a   = 'FooBar' 
    b-c = 9 
    b-d = '3.14' ).

Справочная документация для получения дополнительной информации:


ЧАСТЬ 2:

Ваш код с CALL TRANSFORMATION ID не работает по двум причинам:

  1. JSON всегда должен быть JSON объект с именами членов root (RESULT rootname1 = var1 rootname2 = var2). Вы определили только один root с именем "XML", поэтому JSON должно быть что-то вроде {"X-ML":...} (это X-ML, а не XML из-за указанных c ABAP причина )
  2. Имена компонентов ABAP хранятся внутри SAP в верхнем регистре (A, B, C, D), а преобразование идентификатора ID чувствительно к регистру в отношении имен элементов , поэтому данные JSON должны иметь имена членов в верхнем регистре (у вас все имена в нижнем регистре a, b, c, d).

Иначе говоря, ваш код может работать если ваш ввод JSON содержит это значение:

lv_xmls = '{"X-ML":{"A":"FooBar","B":{"C":9,"D":3.14}}}'.

Другое решение может состоять в создании пользовательского преобразования идентификатора, которое будет преобразовывать имена JSON членов в верхний регистр и добавлять фиктивный элемент root. Но это другая история.

1 голос
/ 26 февраля 2020

Я не хороший разработчик ABAP, поэтому я не знаю, есть ли лучший код для этого, но это сработало для меня:

    TYPES: BEGIN OF json_subobject,
         c TYPE i,
         d TYPE decfloat34,
       END OF json_subobject.
TYPES: BEGIN OF json_object,
         a TYPE c LENGTH 10,
         b TYPE json_subobject,
       END OF json_object.

DATA: foo TYPE json_object,
      writer TYPE REF TO cl_sxml_string_writer,
      json TYPE xstring.

DATA: lv_xmls TYPE string VALUE '{"a":"FooBar","b":{"c":9,"d":3.14}}',
      lv_xmlb TYPE xstring.

*TRY.
*    lv_xmlb = cl_abap_codepage=>convert_to(
*                source      = lv_xmls
*                codepage    = `UTF-8`
*                endian      = space
*                replacement = '#'
*                ignore_cerr = abap_false ).
*  CATCH cx_parameter_invalid_range cx_sy_codepage_converter_init cx_sy_conversion_codepage cx_parameter_invalid_type.
*    ENDTRY.



WRITE: |Deserializing JSON ...|.
NEW-LINE.

cl_fdt_json=>json_to_data( EXPORTING iv_json = lv_xmls
CHANGING ca_data = foo ).

WRITE: '{'.
NEW-LINE.
WRITE: |  "a": "{ foo-a }",|.
NEW-LINE.
WRITE: |  "b": \{|.
NEW-LINE.
WRITE: |    "c": { foo-b-c },|.
NEW-LINE.
WRITE: |    "d": { foo-b-d },|.
NEW-LINE.
WRITE: |  \}|.
NEW-LINE.
WRITE: |\}|.

Этот код просто преобразовывает массив JSON на внутренний стол.

...