ABAP 接口开发:ABAP 数据和 JSON 的互相转化

494 阅读4分钟

如今,JSON 格式正被广泛使用。您最终会需要使用 SAP ABAP 来解释 JSON 数据或创建 JSON 数据。

在本篇文章中,您将了解如何做到这一点。

  • 验证 JSON
  • 读取 JSON
  • 创建 JSON

首先,让我们看看什么是 JSON 数据。你可以访问 json.org 了解有关 JSON 的更多信息。下面是一个简短的版本。

  • JSON - JavaScript 对象符号
  • 它是一种轻量级数据交换格式
  • 便于人类读写
  • 便于机器解析和生成
  • 它基于 JavaScript 编程语言标准的一个子集
  • JSON 基于两种结构
    • 键-值对的集合
    • 值的有序列表

JSON 示例

第一个示例有一组键和值对。这些值对分别是 name&Amarage&18 以及 city & Mumbai

{
	"name": "Amar",
	"age": 18,
	"city": "Mumbai"
}

下面的第二个示例显示了第一个示例中的集合列表。JSON 中的每个值既可以是直接值,也可以是包含在 [ ]中的键-值对/集合列表,并用逗号" ,"分隔。

{
	"students": [{
			"name": "Amar",
			"age": 18,
			"city": "Mumbai"
		},
		{
			"name": "Akbar",
			"age": 17,
			"city": "Mumbai"
		},
		{
			"name": "Anthony",
			"age": 16,
			"city": "Mumbai"
		}
	]
}

jsonlint.com/jsonformatter.org/ 等网站可用于验证 JSON 数据或格式化 JSON 数据,以便我们进行测试。

JSON vs XML

JSON 与 XML 非常相似,都是人类可读的,都是分层的,都可用于各种编程语言。但 JSON 比 XML 更简单,它不使用结束标记,因此更短、读写更简单。

现在,让我们回到如何在 ABAP 中处理 JSON。

在 ABAP 中验证 JSON 数据

ABAP 中用于处理 JSON 的类是 cl_sxml_string_reader。由于 JSON 和 XML 相似,因此两者使用相同的类。

代码示例:

REPORT zjson_learning.

DATA : lv_json TYPE string VALUE '{"name": "Amar","age":18,"city": "Mumbai"}'.

DATA(lo_reader) = cl_sxml_string_reader=>create( cl_abap_codepage=>convert_to( lv_json ) ).
TRY.
    lo_reader->next_node( ).
    lo_reader->skip_node( ).
    cl_demo_output=>display( 'JSON is valid' ).
  CATCH cx_sxml_parse_error INTO DATA(lx_parse_error).
    cl_demo_output=>display( lx_parse_error->get_text( ) ).
ENDTRY.

当 JSON 有效时,我们会得到以下输出:

image.png

然后更改 JSON 文件,尝试使用无效 JSON,得到如下输出结果。

DATA : lv_string TYPE string VALUE '{"name": "Amar","age":18,"city": "Mumbai"1}'.

然后更改 JSON 文件,尝试使用无效 JSON,得到如下输出结果:

image.png

使用 ABAP 读取 JSON

读取具有线性结构的 JSON 文件可能不是实际用例,但有助于理解代码块。

TYPES :
  BEGIN OF ty_student,
    name TYPE string,
    age  TYPE i,
    city TYPE string,
  END OF ty_student.

DATA : lv_json    TYPE string VALUE '{"name": "Amar","age":18,"city": "Mumbai"}',
       lr_data    TYPE REF TO data,
       ls_student TYPE ty_student.

/ui2/cl_json=>deserialize(
  EXPORTING
    json         = lv_json
    pretty_name  = /ui2/cl_json=>pretty_mode-user
    assoc_arrays = abap_true
  CHANGING
    data         = lr_data ).

IF lr_data IS BOUND.

  ASSIGN lr_data->* TO FIELD-SYMBOL(<lfs_data>).

  DO 3 TIMES. "Number of fields

    CASE sy-index.
      WHEN 1. DATA(lv_fname) = 'NAME'.
      WHEN 2. lv_fname = 'AGE'.
      WHEN 3. lv_fname = 'CITY'.
    ENDCASE.

    ASSIGN COMPONENT sy-index OF STRUCTURE ls_student TO FIELD-SYMBOL(<lfs_field>).
    ASSIGN COMPONENT lv_fname OF STRUCTURE <lfs_data> TO FIELD-SYMBOL(<lfs_ref_value>).
    IF <lfs_ref_value> IS ASSIGNED AND <lfs_field> IS ASSIGNED.
      lr_data = <lfs_ref_value>.
      ASSIGN lr_data->* TO FIELD-SYMBOL(<lfs_actual_value>).
      IF <lfs_actual_value> IS ASSIGNED.
        <lfs_field> = <lfs_actual_value>.
      ENDIF.
    ENDIF.
  ENDDO.

  cl_demo_output=>display( ls_student ).

ENDIF.

输出结果:

image.png

当我们知道需要表格形式的数据时,我们可以使用内部表格而不是结构。我们需要不断地将数据从数据引用移动到字段符号,以读取数据值。

TYPES :
  BEGIN OF ty_student,
    name TYPE string,
    age  TYPE i,
    city TYPE string,
  END OF ty_student.

DATA : lv_json    TYPE string,
       lr_data    TYPE REF TO data,
       ls_student TYPE ty_student,
       lt_student TYPE STANDARD TABLE OF ty_student.

FIELD-SYMBOLS : <lfs_table> TYPE ANY TABLE.


"Prepare JSON string for testing

lv_json = '{"students": [{"name": "Amar","age": 18,"city": "Mumbai"},' &&
          '{"name": "Akbar","age": 17,"city": "Mumbai"},' &&
          '{"name": "Anthony","age": 16,"city": "Mumbai"} ] }'.

/ui2/cl_json=>deserialize(
  EXPORTING
    json         = lv_json
    pretty_name  = /ui2/cl_json=>pretty_mode-user
    assoc_arrays = abap_true
  CHANGING
    data         = lr_data ).

IF lr_data IS BOUND.

  ASSIGN lr_data->* TO FIELD-SYMBOL(<lfs_data>).
  ASSIGN COMPONENT 'STUDENTS' OF STRUCTURE <lfs_data> TO FIELD-SYMBOL(<lfs_results>).
  ASSIGN <lfs_results>->* TO <lfs_table>.

  LOOP AT <lfs_table> ASSIGNING FIELD-SYMBOL(<lfs_row>).

    DO 3 TIMES. "Number of fields

      CASE sy-index.
        WHEN 1. DATA(lv_fname) = 'NAME'.
        WHEN 2. lv_fname = 'AGE'.
        WHEN 3. lv_fname = 'CITY'.
      ENDCASE.

      ASSIGN COMPONENT sy-index OF STRUCTURE ls_student TO FIELD-SYMBOL(<lfs_field>).

      ASSIGN <lfs_row>->* TO FIELD-SYMBOL(<lfs_row_val>).
      ASSIGN COMPONENT lv_fname OF STRUCTURE <lfs_row_val> TO FIELD-SYMBOL(<lfs_ref_value>).
      IF <lfs_ref_value> IS ASSIGNED AND <lfs_field> IS ASSIGNED.
        ASSIGN <lfs_ref_value>->* TO FIELD-SYMBOL(<lfs_actual_value>).
        IF <lfs_actual_value> IS ASSIGNED.
          <lfs_field> = <lfs_actual_value>.
        ENDIF.
      ENDIF.
    ENDDO.

    APPEND ls_student TO lt_student.

  ENDLOOP.

  cl_demo_output=>display( lt_student ).

ENDIF.

这是最佳解决方案吗?也许不是,但它足以让我们开始构建一个解决方案。

使用 ABAP 创建 JSON

SELECT * FROM scarr INTO TABLE @DATA(lt_scarr) UP TO 3 ROWS  .

DATA(lv_json) = /ui2/cl_json=>serialize(
  data        = lt_scarr
  compress    = abap_true
  pretty_name = /ui2/cl_json=>pretty_mode-camel_case ).

" Display JSON in ABAP
CALL TRANSFORMATION sjson2html SOURCE XML lv_json
                           RESULT XML DATA(lvc_html).
cl_abap_browser=>show_html(
  title = 'Sample JSON'
  html_string = cl_abap_codepage=>convert_from( lvc_html ) ).

image.png

还有更多选择。

CALL TRANSFORMATION

在上面的示例中,我们使用转换将 json 显示为 HTML。在这里,我们将把它用作 itab 到 JSON 的转换。

SELECT * FROM scarr INTO TABLE @DATA(lt_scarr).

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

CALL TRANSFORMATION id
  SOURCE values = lt_scarr
  RESULT XML lo_writer.

cl_abap_conv_in_ce=>create( )->convert(
  EXPORTING
    input = lo_writer->get_output( )
  IMPORTING
    data = lv_json ).

在调试模式下,JSON 字符串显示如下。

image.png

然后可以使用相同的 json 字符串来测试反向转换。

CLEAR lt_scarr.
CALL TRANSFORMATION id
  SOURCE XML lv_json
  RESULT values = lt_scarr.

cl_demo_output=>display( lt_scarr ).

执行结果:

image.png

下一步是研究 CL_SXML_TABLE_READER 类,以及如何使用它来获取特定数据。SAP 在软件包 SXML_DEMO 中创建了示例程序,并创建了以 DEMO_JSON_* 开头的程序。

image.png