Inhaltsverzeichnis
This is an old version of this page. To the new page please click here
Das ist eine alte Version dieser Seite. Zur neuen Seite klicken sie hier
einfache JSON - Erstellung
Die Klasse /EPO1/CL_TOOLS stellt die Methode ABAP_TO_JSON bereit, mit der eine beliebige ABAP - Struktur nach JSON umgewandelt werden kann. Primitive Werte (Zahlen, Zeichenketten, Tabellen etc.) ohne Struktur können nicht verarbeitet werden - es ist zumindest eine Struktur mit einem Strukturelement notwendig.
Beispiel - Typdefinition und Datendefinition:
TYPES:
lty_char_tab TYPE STANDARD TABLE OF char10 WITH KEY table_line,
BEGIN OF lty_struc, " Struktur mit primitiven Elementen und Tabellen
eins TYPE i,
zwei TYPE char10,
drei TYPE string,
vier TYPE xstring,
fuenf TYPE lty_char_tab,
sechs TYPE lty_char_tab, " diese Tabelle bleibt leer
END OF lty_struc,
BEGIN OF lty_json,
a TYPE i,
b TYPE char10,
c TYPE lty_struc,
END OF lty_json.
DATA:
ls_json TYPE lty_json, " ABAP - Struktur
lv_json TYPE string. " JSON - String
Beispieldaten:
ls_json-a = 5.
ls_json-b = 'Ab/\"'.
ls_json-c-eins = 7.
ls_json-c-zwei = 'dummy!{\}'.
CONCATENATE
'Text mit Tabulator'
cl_abap_char_utilities=>horizontal_tab
'und Zeilenumbruch'
cl_abap_char_utilities=>newline
'ENDE'
INTO ls_json-c-drei.
ls_json-c-vier = '0A000D00000A000D'.
APPEND 'test1' TO ls_json-c-fuenf.
APPEND 'test2' TO ls_json-c-fuenf.
APPEND 'test3' TO ls_json-c-fuenf.
Beispiel Aufruf:
CALL METHOD /epo1/cl_tools=>abap_to_json(
EXPORTING
i_any = ls_json " beliebige ABAP Datenstruktur
i_strip_initial = 'X' " keine leeren Elemente ausgeben
IMPORTING
e_json = lv_json " JSON Ergebnisstring
).
Ergebnisbeispiel:
{"A":5,"B":"Ab/\\\"","C":{"EINS":7,"ZWEI":"dummy!{\\}","DREI":"Text mit Tabulator\tund Zeilenumbruch\nENDE","VIER":"CgANAAAKAA0=","FUENF":["test1","test2","test3"],"SECHS":[]}}
Formatierung
Die Methode MAP hat noch weitere optionale Parameter für die Formatierung des JSON - Strings zur besseren Lesbarkeit:
- Zeilenumbruch einschalten
i_line_break = 'X'
- zusätzlich eine Einrückung generieren
i_intent = 'X'
Beispiel für Zeilenumbruch:
{
"A":5,
"B":"Ab/\\\"",
"C":
{
"EINS":7,
"ZWEI":"dummy!{\\}",
"DREI":"Text mit Tabulator\tund Zeilenumbruch\nENDE",
"VIER":"CgANAAAKAA0=",
"FUENF":
[
"test1",
"test2",
"test3"
],
"SECHS":
[]
}
}
Beispiel für Zeilenumbruch und Einrückung:
{
"A":5,
"B":"Ab/\\\"",
"C":
{
"EINS":7,
"ZWEI":"dummy!{\\}",
"DREI":"Text mit Tabulator\tund Zeilenumbruch\nENDE",
"VIER":"CgANAAAKAA0=",
"FUENF":
[
"test1",
"test2",
"test3"
],
"SECHS":
[]
}
}
Feldmapping mit Transformation
Wenn das generierte JSON als Request für ein Webservice benutzt wird, müssen die Feldnamen dem angebotenen API entsprechen. Über eine kundenspezifische Transformation können die Feldnamen beliebig gemappt werden.
In diesem Beispiel wollen wir das ABAP - Feld 'A' auf das JSON - Feld 'a' mappen, und 'B' auf 'be'. Zu beachten ist, daß die Transformation auf ein JSON-XML angewendet wird, hier stehen die Feldnamen jeweils im Attribut 'name'.
Das äusserste JSON-Objekt mit dem Namen 'ABAP_VALUES ist ein intern benutztes Hilfsobjekt, dieses wird vor der JSON-Ausgabe wieder entfernt.
Beispiel - JSON-XML (für die Daten lt. obigem Beispiel)
Hinweis: dieses XML wird SAP-intern generiert und muß nicht selbst erstellt werden
<?xml version="1.0" encoding="utf-8"?>
<object>
<object name="ABAP_VALUES">
<num name="A">5</num>
<str name="B">Ab/\"</str>
<object name="C">
<num name="EINS">7</num>
<str name="ZWEI">dummy!{\}</str>
<str name="DREI">Text mit Tabulator und Zeilenumbruch
ENDE</str>
<str name="VIER">CgANAAAKAA0=</str>
<array name="FUENF">
<str>test1</str>
<str>test2</str>
<str>test3</str>
</array>
</object>
</object>
</object>
Beispiel - Transformation: das Feld 'A' wird auf 'a' gemappt, das Feld 'B' auf 'be'
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="UTF-8" indent="yes" method="xml" version="1.0"/>
<!-- default - template (simple copy) -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@name">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
<xsl:attribute name="name">
<xsl:choose>
<xsl:when test="current() = string('A')">
<xsl:value-of select="string('a')"/>
</xsl:when>
<xsl:when test="current() = string('B')">
<xsl:value-of select="string('be')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:template>
</xsl:transform>
Aufruf mit kundenspezifischer Transformation:
CALL METHOD /epo1/cl_tools=>abap_to_json(
EXPORTING
i_any = ls_json
i_line_break = 'X'
i_intent = 'X'
i_strip_initial = 'X'
i_transformation = 'Z_JSON_MAPPING' " Transformation entsprechend dem Beispiel
IMPORTING
e_json = lv_json
).
Ergebnis:
{
"a":5,
"be":"Ab/\\\"",
"C":
{
"EINS":7,
"ZWEI":"dummy!{\\}",
"DREI":"Text mit Tabulator\tund Zeilenumbruch\nENDE",
"VIER":"CgANAAAKAA0=",
"FUENF":
[
"test1",
"test2",
"test3"
]
}
}
Feldmapping mit Customizingtabelle
Die fertig ausgelieferte Transformation /EPO1/EXC_JSON_FIELD_MAPPING erlaubt es, gemeinsam mit der Customizingtabelle /EPO1/FIELD_MAP das Mapping der ABAP-Felder auf JSON Feldnamen durchzuführen. Hier wird die statische Methode MAP der Klasse /EPO1/CL_FIELD_NAME_MAPPING benutzt, um über die Customizingtabelle das Mapping durchführt.
Vorteil ist, daß man hierzu keine Transformation schreiben muß, sondern mit einfachem Customizing (Transaktion SM30) auskommt.
Eine Voraussetzung für ein erfolgreiches Mapping ist, daß die Felder in der ABAP Struktur eindeutige Namen haben, wenn die JSON Feldnamen unterschiedlich sein sollen.
Mappingtabelle /EPO1/FIELD_MAP
Schlüssel ist der Name des EPO Services, die Richtung (eingehend: JSON nach ABAP / ausgehend: ABAP nach JSON) und der Name des zu mappenden Feldes innerhalb der ABAP Struktur.
Beispiel: das ABAP - Feld 'A' wird auf das JSON-Feld 'Ahhh' gemappt, und 'B' nach 'bEee'. Als Servicenamen nehmen wir entweder ein bereits eingerichtetes EPO-Service, oder einen beliebigen Identifier - z.B. 'JSON_API':
Service Name | Richtung | ABAP | JSON |
---|---|---|---|
JSON_API | O | A | Ahhh |
JSON_API | O | B | bEee |
Nun der Beispiel - Aufruf: Die Transformation und der JSON-API-Name werden als Parameter übergeben
CALL METHOD /epo1/cl_tools=>abap_to_json(
EXPORTING
i_any = ls_json
i_line_break = 'X'
i_intent = 'X'
i_strip_initial = 'X'
i_transformation = '/EPO1/EXC_JSON_FIELD_MAPPING' " ausgelieferte Transformation
i_service_id = 'JSON_API' " EPO-Service ID, entsprechend der Customizingtabelle
IMPORTING
e_json = lv_json
).
..und das JSON - Ergebnis dazu:
{
"Ahhh":5,
"bEee":"Ab/\\\"",
"c":
{
"eins":7,
"zwei":"dummy!{\\}",
"drei":"Text mit Tabulator\tund Zeilenumbruch\nENDE",
"vier":"CgANAAAKAA0=",
"fuenf":
[
"test1",
"test2",
"test3"
]
}
}
Mappingtabelle /EPO1/FIELD_MAP - Konvertierungen
Optional kann in der Mappingtabelle eine Konvertiermethode für jene Felder eingetragen werden, für die es kein explizites Mapping gibt. Dazu erstellt man ein Eintrag mit einem leeren ABAP Feldnamen und einem der folgenden Schlüsselworte im externen JSON Feldnamen:
- lowercase - übersetzt ABAP in JSON Kleinbuchstaben
- UPPERCASE - übersetzt ABAP in JSON Großbuchstaben (dies ist das Defaultverhalten)
- camelCase - übersetzt ABAP in JSON Kleinbuchstaben, ein Unterstrich mit nachfolgendem Buchstaben wird in einen Großbuchstaben umgewandelt
- Beispiel: ABAP 'USER_NAME' wird nach JSON 'userName' umgesetzt
- CamelCase - ..detto, das erste Zeichen wird auch in einen Großbuchstaben umgewandelt
- Beispiel: ABAP 'USER_NAME' wird nach JSON 'UserName' umgesetzt
zurück von JSON nach ABAP
Die Klasse /EPO1/CL_TOOLS bietet analog die Methode JSON_TO_ABAP, mit der ein JSON in eine beliebige ABAP Struktur übergeführt werden kann. Auch hier gibt es die Möglichkeit, eine eigene Transformation anzugeben und auch das Feldmapping über die Customizingtabelle zu steuern.
Zu beachten ist, daß nur jene ABAP-Felder befüllt werden, deren Namen passen.
Simples Mapping
Beispielstruktur und Beispiel-JSON können aus dem obigen Beispiel entnommen werden
CALL METHOD /epo1/cl_tools=>json_to_abap
EXPORTING
i_json = lv_json
IMPORTING
e_any = ls_json
.
Dieses Beispiel funktioniert nur, wenn die ABAP - Strukturnamen genau den JSON - Feldnamen entsprechen (die JSON-Feldnamen dürfen auch klein geschrieben sein).
Mapping mit einer selbst geschriebenen Transformation
Die Transformation muß das Mapping in der Gegenrichtung durchführen. Analog dem obigen Beispiel wird hier das JSON-Feld 'a' auf das ABAP-Feld 'A' gemappt, und 'be' auf 'B':
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="UTF-8" indent="yes" method="xml" version="1.0"/>
<!-- default - template (simple copy) -->
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- Alle NAME - Attribute mappen
Die Zuweisung des Attributnamens darf erst nach dem COPY erfolgen, sonst
wird der Wert wieder überschrieben -->
<xsl:template match="@name">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
<xsl:attribute name="name">
<xsl:choose>
<xsl:when test="current() = string('a')">
<xsl:value-of select="string('A')"/>
</xsl:when>
<xsl:when test="current() = string('be')">
<xsl:value-of select="string('B')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:template>
</xsl:transform>
Aufruf mit kundenspezifischer Transformation:
CALL METHOD /epo1/cl_tools=>json_to_abap
EXPORTING
i_json = lv_json
i_transformation = 'Z_JSON_MAPPING_2' " Transformation entsprechend dem Beispiel
IMPORTING
e_any = ls_json
.
Transformation mit Mappingtabelle
Die Richtung JSON nach ABAP wird in der Mappingtabelle /EPO1/FIELD_MAP mit der Richtung 'I' angesprochen, es kommt wieder die ausgelieferte Transformation /EPO1/EXC_JSON_NAME_MAPPING zum Einsatz.
Um die Beispiel-Struktur aus dem obigen Beispiel befüllen zu können, müssen die 'O'-Einträge der Customizingtabelle /EPO1/FIELD_MAP auf 'I'-Einträge kopiert werden. Üblicherweise wird ein Response aber anders aufgebaut sein als ein Request, somit sind die Feldnamen meist unterschiedlich.
Service Name | Richtung | ABAP | JSON |
---|---|---|---|
JSON_API | I | A | Ahhh |
JSON_API | I | B | bEee |
JSON nach ABAP mit Mappingtabelle:
CALL METHOD /epo1/cl_tools=>json_to_abap
EXPORTING
i_json = lv_json
i_transformation = '/EPO1/EXC_JSON_NAME_MAPPING' " ausgelieferte Transformation
i_service_id = 'JSON_API' " EPO-Service ID, entsprechend der Customizingtabelle
IMPORTING
e_any = ls_json
.