Настройте JSON, созданный CL_SXML_STRING_WRITER - PullRequest
2 голосов
/ 29 марта 2019

Я создаю JSON таким образом, чтобы извлечь любую таблицу (имя «случайно» определяется во время выполнения, ее имя находится в переменной iv_table_name):

FIELD-SYMBOLS <itab> TYPE STANDARD TABLE.
DATA ref_itab TYPE REF TO data.

DATA(iv_table_name) = 'SCARR'.
CREATE DATA ref_itab TYPE STANDARD TABLE OF (iv_table_name).
ASSIGN ref_itab->* TO <itab>.

SELECT *
  INTO TABLE <itab>
  FROM (iv_table_name).

DATA results_json TYPE TABLE OF string.
DATA sub_json TYPE string.

DATA(lo_json_writer) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).

CALL TRANSFORMATION id
        SOURCE result = <itab>
        RESULT XML lo_json_writer.

cl_abap_conv_in_ce=>create( )->convert( 
        EXPORTING
          input = lo_json_writer->get_output( )
        IMPORTING
          data = sub_json ).

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

{"RESULT":
 [
   {"MANDT":"220","AUFNR":"0000012", ...},
   {"MANDT":"220","AUFNR":"0000013", ...},
   ...
  ]
}

Есть ли способ избежать окружающего словаря и получить такой результат?

 [
   {"MANDT":"220","AUFNR":"0000012", ...},
   {"MANDT":"220","AUFNR":"0000013", ...},
   ...
  ]

Фон:

Я использовал это:

sub_json = /ui2/cl_json=>serialize( data = <lt_result> pretty_name = /ui2/cl_json=>pretty_mode-low_case ).

Но производительность /ui2/cl_json=>serialize( ) нехороша.

Ответы [ 4 ]

2 голосов
/ 31 марта 2019

Если вы действительно хотите использовать его просто как инструмент для извлечения записей таблицы, тогда вы можете написать собственное преобразование ID в STRANS.Это может выглядеть так, давайте назовем это Z_JSON_TABLE_CONTENTS (создайте его с типом XSLT):

<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:sap="http://www.sap.com/sapxsl"
>

<xsl:output method="text" encoding="UTF-8" />

<xsl:strip-space elements="*"/>

<xsl:template match="RESULT">
  [
    <xsl:for-each select="*">
      {
      <xsl:for-each select="*">
        &quot;<xsl:value-of select="local-name()" />&quot;: &quot;<xsl:value-of select="text()" />&quot;<xsl:if test="position() != last()">,</xsl:if>
      </xsl:for-each>
      }<xsl:if test="position() != last()">,</xsl:if>
    </xsl:for-each>
  ]
</xsl:template>

</xsl:transform>

Тогда вы можете использовать это так.

REPORT ZZZ.

FIELD-SYMBOLS <itab> TYPE STANDARD TABLE.
DATA ref_itab TYPE REF TO data.

DATA(iv_table_name) = 'SCARR'.
CREATE DATA ref_itab TYPE STANDARD TABLE OF (iv_table_name).
ASSIGN ref_itab->* TO <itab>.

SELECT *
  INTO TABLE <itab>
  FROM (iv_table_name).

DATA results_json TYPE TABLE OF string.
DATA sub_json TYPE string.

DATA g_string TYPE string.
DATA(g_document) = cl_ixml=>create( )->create_document( ).
DATA(g_ref_stream_factory) = cl_ixml=>create( )->create_stream_factory( ).
DATA(g_ostream) = g_ref_stream_factory->create_ostream_cstring( g_string ).

CALL TRANSFORMATION Z_JSON_TABLE_CONTENTS
        SOURCE result = <itab>
        RESULT XML g_ostream.

DATA(g_json_parser) = new /ui5/cl_json_parser( ).
g_json_parser->parse( g_string ).
1 голос
/ 29 мая 2019

Просто немного ручной работы и вуаля!

DATA(writer) = CAST if_sxml_writer( cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ) ).

DATA(components) =
CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( iv_table_name ) )->components.

writer->open_element( name = 'object' ).
LOOP AT <itab> ASSIGNING FIELD-SYMBOL(<line>).
 LOOP AT components ASSIGNING FIELD-SYMBOL(<fs_comp>).
  ASSIGN COMPONENT <fs_comp>-name OF STRUCTURE <line> TO FIELD-SYMBOL(<fs_val>).
  writer->open_element( name = 'str' ).
  writer->write_attribute( name = 'name' value = CONV string( <fs_comp>-name ) ).
  writer->write_value( CONV string( <fs_val> ) ).
  writer->close_element( ).
 ENDLOOP.
ENDLOOP.
writer->close_element( ).

DATA(xml_json) = CAST cl_sxml_string_writer( writer )->get_output(  ).  
sub_json = cl_abap_codepage=>convert_from( source = xml_json codepage = `UTF-8` ).

Нет окружающего списка и словаря. Если вы хотите каждую строку в отдельном словаре, это легко настраивается.

1 голос
/ 30 марта 2019

У меня нет ответа, возможно ли опустить начальный тег "RESULT" в полном sXML, но я считаю, что нет.

Теперь есть решение с принципом KISS * 1004.*:

REPLACE ALL OCCURRENCES OF REGEX '^\{"RESULT":|\}$' IN sub_json WITH ``.

Существует также другая запись (немного медленнее):

sub_json = replace( val = sub_json regex = '^\{"RESULT":|\}$' with = `` occ = 0 ).

ADDENDUM о производительности:

Я измерил это для строки из 880K символов,следующий код с точным количеством позиций для удаления (10 ведущих символов и 1 конечный символ) в 6 раз быстрее, чем регулярное выражение (может варьироваться в зависимости от версии ядра ABAP), но, возможно, это не будет заметно по сравнению с остальнымипрограмма:

SHIFT sub_json LEFT BY 10 PLACES CIRCULAR.
REPLACE SECTION OFFSET strlen( sub_json ) - 11 OF sub_json WITH ``.
0 голосов
/ 01 апреля 2019

Если вы используете ID преобразование вызова, то любой узел, который вы дадите при преобразовании, будет добавлен по умолчанию. Мы не можем пропустить это, но вы можете удалить следующим образом ..

Заменить : используя регулярное выражение или прямое слово с оператором Заменить первое вхождение и следующую последнюю закрывающую скобку }. То, как ты это сделал.

НАЙТИ : Вы можете просто использовать это ниже заявление FIND REGEX '(\[.*\])' in sub_json SUBMATCHES sub_json.

...