This is a test message to test the length of the message box.
Login
ABAP Tipp Konvertierung JSON nach Intern
Erstellt von Software-Heroes

ABAP Tipp - Konvertierung JSON nach Intern

455

In diesem kleinen Tipp gehen wir darauf ein, wie du einen JSON Stream in ein internes Format konvertierst und dann ordentlich verwenden kannst.

Werbung


Wenn du heute an die Schnittstellenlandschaft denkst, wirst du wohl oder übel nicht an OData vorbeikommen. Ebenso wenn du ein Cloud System wie Ariba oder Successfactors anbinden möchtest. All diese Systeme haben gleich, dass sie mit REST Schnittstellen kommunizieren. Doch wie verarbeitest du die Antwortdaten, wenn du mal so einen Service per HTTP Request aus ABAP ansprichst? Darauf gehen wir heute etwas genauer ein.

 

Vorbereitung

Im ersten Schritt bauen wir uns ein passendes JSON auf, dass aus verschiedenen Datentypen besteht und dazu noch intern eine Tabelle verwendet, damit wir auch mit einer tiefen/verschachtelten Struktur arbeiten können. Unser Beispielaufbau könnte also wie folgt aussehen:

 

Nachdem wir nun ein zu konvertierenden JSON String haben, wollen wir dieses auch innerhalb eines Programmlaufs konvertieren und eine interne Struktur befüllen. Diese Struktur können wir uns ebenso im ABAP aufbauen, dazu benötigen wir verschiedene Typen.

TYPES:
  BEGIN OF ts_subdata,
    key   TYPE string,
    value TYPE string,
  END OF ts_subdata,
  tt_subdata TYPE STANDARD TABLE OF ts_subdata WITH EMPTY KEY,

  BEGIN OF ts_data,
    text   TYPE string,
    number TYPE i,
    bool   TYPE abap_bool,
    table  TYPE tt_subdata,
  END OF ts_data.

 

Strukturzuweisung

Dies ist die einfachste Form der Konvertierung, du musst allerdings immer wissen wie deine Daten aussehen, um so an den Inhalt heranzukommen. Der Aufbau von verschachtelten Strukturen kann ebenso einiges an Zeit in Anspruch nehmen. Im nächsten Schritt können wir den String bereits mit der Methode Parsen.

DATA:
  ls_data TYPE ts_data.

/ui2/cl_json=>deserialize(
  EXPORTING
    json             = id_json
  CHANGING
    data             = ls_data
).

 

Wir erzeugen uns eine Struktur von unserem Zieltyp und verwenden dann die DESERIALIZE Methode der Klasse /UI2/CL_JSON, um die Konvertierung durchzuführen. Die Daten werden sauber in die Felder und die Tabelle gemappt, Element die in unserer Struktur fehlen, werden einfach übersprungen und wir können uns auf die wichtigen Inhalte konzentrieren.

 

Das Feld ADD_TEXT wird nicht gemappt, führt aber auch nicht zu einem Fehler. Das Feld BOOL wurde sauber nach ABAP_TRUE konvertiert. Damit steht uns eine einfache Art der Konvertierung zur Verfügung.

 

Generische Methode

Ebenso können wir eine Konvertierung komplett generisch durchführen, die Methode kann auch eine Referenz auf die Daten erzeugen, wenn wir keinen strukturierten Typen übergeben. Das Ergebnis einer solchen Konvertierung sieht im Eclipse Debugger wie folgt aus.

 

Auf solche komplett generischen Daten können wir nicht einfach zur Laufzeit zugreifen, da das System nicht weiß wie der Datentyp aufgebaut ist. Wir können aber über eine generische Verarbeitung auf die Daten zugreifen und diese mappen. In unserem Beispiel wollen wir einmal auf unser nicht benötigtes Element zugreifen und die Tabelle innerhalb der Struktur mappen.

DATA:
  lr_data     TYPE REF TO data,
  ld_add_text TYPE string,
  lt_subdata  TYPE tt_subdata.
FIELD-SYMBOLS:
  <lt_table> TYPE STANDARD TABLE.

/ui2/cl_json=>deserialize(
  EXPORTING
    json             = id_json
  CHANGING
    data             = lr_data
).

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

" Map the ADD_TEXT field
ASSIGN COMPONENT 'ADD_TEXT' OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<ld_add>).
ASSIGN <ld_add>->* TO FIELD-SYMBOL(<ld_add_value>).
ld_add_text = <ld_add_value>.

" Map internal table 
ASSIGN COMPONENT 'TABLE' OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<lt_table_ref>).
ASSIGN <lt_table_ref>->* TO <lt_table>.

LOOP AT <lt_table> ASSIGNING FIELD-SYMBOL(<ls_line>).
  ASSIGN <ls_line>->* TO FIELD-SYMBOL(<ls_line_value>).

  ASSIGN COMPONENT 'KEY' OF STRUCTURE <ls_line_value> TO FIELD-SYMBOL(<ld_key>).
  ASSIGN COMPONENT 'VALUE' OF STRUCTURE <ls_line_value> TO FIELD-SYMBOL(<ld_value>).

  ASSIGN <ld_key>->* TO FIELD-SYMBOL(<ld_key_value>).
  ASSIGN <ld_value>->* TO FIELD-SYMBOL(<ld_value_value>).

  INSERT VALUE #(
    key   = <ld_key_value>
    value = <ld_value_value>
  ) INTO TABLE lt_subdata.
ENDLOOP.

 

Ganz schön viel Code und viele ASSIGNs wirst du dir sicherlich denken. Jedes Element ist eine Referenz und muss doppelt gebunden werden, um an den eigentlichen Wert und die eigentlichen Daten zu gelangen. Du wirst uns sicherlich zustimmen, dass dieser Weg nicht besonders einfach ist und viele Fallen bereithält. Ebenso fehlt noch die gesamte Fehlerbehandlung im oberen Stück Quellcode, diese würde noch einmal die gleiche Anzahl Zeilen wegnehmen.

 

Beispiel

An dieser Stelle noch einmal die vollständige Beispielklasse, wie wir sie in den Beispielen verwenden.

CLASS zcl_60bs_test_json_convert DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PROTECTED SECTION.
  PRIVATE SECTION.
    TYPES:
      BEGIN OF ts_subdata,
        key   TYPE string,
        value TYPE string,
      END OF ts_subdata,
      tt_subdata TYPE STANDARD TABLE OF ts_subdata WITH EMPTY KEY,

      BEGIN OF ts_data,
        text   TYPE string,
        number TYPE i,
        bool   TYPE abap_bool,
        table  TYPE tt_subdata,
      END OF ts_data.

    METHODS:
      convert_json_with_structured
        IMPORTING
          id_json TYPE string,

      convert_json_with_reference
        IMPORTING
          id_json TYPE string.
ENDCLASS.

CLASS zcl_60bs_test_json_convert IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    DATA(ld_json) = `{"text":"Some text","number":123, "bool":"TRUE", "add_text":"Text number 2", "table":[{"key":"One","value":"1"},{"key":"Two","value":"2"}]}`.

    convert_json_with_structured( ld_json ).
    convert_json_with_reference( ld_json ).
  ENDMETHOD.


  METHOD convert_json_with_structured.
    DATA:
      ls_data TYPE ts_data.

    /ui2/cl_json=>deserialize(
      EXPORTING
        json             = id_json
      CHANGING
        data             = ls_data
    ).
  ENDMETHOD.


  METHOD convert_json_with_reference.
    DATA:
      lr_data     TYPE REF TO data,
      ld_add_text TYPE string,
      lt_subdata  TYPE tt_subdata.
    FIELD-SYMBOLS:
      <lt_table> TYPE STANDARD TABLE.

    /ui2/cl_json=>deserialize(
      EXPORTING
        json             = id_json
      CHANGING
        data             = lr_data
    ).

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

    ASSIGN COMPONENT 'ADD_TEXT' OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<ld_add>).
    ASSIGN <ld_add>->* TO FIELD-SYMBOL(<ld_add_value>).
    ld_add_text = <ld_add_value>.

    ASSIGN COMPONENT 'TABLE' OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<lt_table_ref>).
    ASSIGN <lt_table_ref>->* TO <lt_table>.

    LOOP AT <lt_table> ASSIGNING FIELD-SYMBOL(<ls_line>).
      ASSIGN <ls_line>->* TO FIELD-SYMBOL(<ls_line_value>).

      ASSIGN COMPONENT 'KEY' OF STRUCTURE <ls_line_value> TO FIELD-SYMBOL(<ld_key>).
      ASSIGN COMPONENT 'VALUE' OF STRUCTURE <ls_line_value> TO FIELD-SYMBOL(<ld_value>).

      ASSIGN <ld_key>->* TO FIELD-SYMBOL(<ld_key_value>).
      ASSIGN <ld_value>->* TO FIELD-SYMBOL(<ld_value_value>).

      INSERT VALUE #(
        key   = <ld_key_value>
        value = <ld_value_value>
      ) INTO TABLE lt_subdata.
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

 

Fazit

Die Konvertierung eines JSON in ABAP kann sehr leicht von der Hand gehen, aber auch einiges an Kopfzerbrechen verursachen, wenn man es versucht dynamisch anzugehen. Wir empfehlen dir die Variante mit der vordefinierten Struktur, da diese viel einfacher umzusetzen ist.


Enthaltene Themen:
TippKonvertierung JSONJSON nach Intern
Kommentare (0)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


ABAP in Praxis - String Verarbeitung

Kategorie - ABAP

In diesem praktischen Beispiel schauen wir uns die String Verarbeitung zur Ermittlung der CDS Namen in CamelCase an und wie du das mit ABAP umsetzen kannst.

15.10.2024

ABAP in der Praxis - Test Driven Development

Kategorie - ABAP

Wie funktioniert eigentlich TDD in der Praxis und gibt es einfache Beispiele zum Lernen in ABAP? In dieser Übung gehen wir auf den praktischen Teil ein.

24.09.2024

ABAP in der Praxis - Datenmenge zusammenführen

Kategorie - ABAP

Wir führen wir zwei unterschiedliche Datenmengen in ABAP zusammen, vor allem im Hinblick auf das Moderne ABAP? Eine praktische Aufgabe zum Thema.

17.09.2024

ABAP in der Praxis - Modern ABAP

Kategorie - ABAP

In dieser kleinen Aufgabe schauen wir uns bestehenden klassischen ABAP Quellcode an und versuchen diesen nach Modern ABAP zu optimieren.

27.08.2024

ABAP Tipp - Performance Datenfilterung

Kategorie - ABAP

Welche Anweisung verwendest du in ABAP zur Filterung von internen Tabellen und ist diese performant? In diesem Artikel mehr dazu.

13.08.2024