Dynamische Tabellenstrukturen im ABAP

Die Objektorientierung mit ABAP®: Vererbung, Dynamische Programmierung, GUI Controls (u.a. ALV im OO).
2 Beiträge • Seite 1 von 1
2 Beiträge Seite 1 von 1

Dynamische Tabellenstrukturen im ABAP

Beitrag von Uwe.Rimarski (ForumUser / 1 / 0 / 1 ) »
Hinweis: Quellcode siehe unten

Auf der Suche nach einer Möglichkeit eine dynamische Tabellenstruktur zu realisieren, habe ich mir echt einen „heißen“ gesucht. Ist schon erstaunlich was einige Kollegen da alles für „Dynamisch“ halten. :)
Hier ist nun endlich eine brauchbare Lösung für ein solches Problem.

Problembeschreibung:
Einlesen von Daten im ASCII Format mit fester Satzlänge. Die Strukturen stehen erst zur Laufzeit fest. Es gibt hierzu auf der SAP Seite weder ein DDICT Objekt dazu, noch ist es möglich eine interne Struktur zu hinterlegen, da sowohl die Daten, als auch die technische Feldbeschreibung der Struktur erst zu Laufzeit des Programms zur Verfügung stehen
Wenn die technische Feldbeschreibung vorliegt, um daraus dann Programm Interne Strukturen auf zu bauen, nennt man diesen Zeitpunkt „Design Zeit“ und nicht Laufzeit.
Somit währe dann ein Tabellenaufbau auch nicht mehr Dynamisch, oder sehr großzügig ausgedrückt: „Teildynamisch“


Gegeben:
Technische Feldbeschreibung der einzulesenden Daten als ASCII Datei zur Programmlaufzeit
Der Aufbau dieser Feldbeschreibung sieht folgendermaßen aus:
Technische Feldbeschreibung = TEC. In der folgenden Dokumentation werden die einzelnen Elemente dieser Struktur mit TEC- angesprochen. TEC-Feldname = Feldname in der technischen Beschreibung

Feldname
Feldtyp
Feldlength
Dezimals
Feldnr


Da stellt sich dann jetzt die frage: „Kleiner Mann, was nun ?“

Hier kommen jedoch die super coolen RTI Tools der SAP als Retter der Situation in spiel. Denn niemand möchte mehr gerne mit „Generate Report“ und ähnlich veralterte Werkzeuge arbeiten. Diese sind sicherlich damals Ihrer zeit weit voraus und toll gewesen, entsprechen aber nicht mehr so ganz den heutigen Anforderungen und Bedürfnissen.

Zunächst muss man verstehen das die Elemente einer Struktur (also die einzelnen Felder ) mit der Klasse CL_ABAP_ELEMDESCR verwaltet werden. Diese Klasse bietet öffentliche Methoden an, um Datentypen im ABAP Kontext anzulegen.

Die Klasse CL_ABAP_STRUCTDESCR verwaltet die Strukturen.
Nun kann man aber nicht die einzelnen Elemente einer Struktur an den Strukturverwalter liefern, und diesen dann bitten eine Struktur daraus zu machen, sondern man muss erst einmal alle Felder der benötigten Struktur mittels des Elementverwalters anlegen und das fertige Feld dann in einen Datenkontainer ablegen. Dieser Datenkontainer ist nichts anderes als wiederum eine Tabelle mit definierter Struktur.
Die Typenbeschreibung dieses Kontainers liegt im Type Pool ABAP ab.
Es handelt sich um die Typen:
ABAP_COMPONENTDESCR das ist die Struktur für jedes Feld einer Tabelle, und
ABAP_COMPONENT_TAB Dies ist die Tabelle oder auch der Datenkontainer für die Felder einer Tabelle


Nachdem die einzelnen Felder mittels des Elementverwalters in den Datenkontainer gestellt wurden,
kann nun der Strukturverwalter gebeten werden, aus diesen Feldern einen Strukturierten Typ zu erstellen.
Dies geschieht mittels der Methode CREATE. Diese erwartet als Importparameter unseren Datenkontainer bzw. unsere Tabelle mit den einzelnen Feldern für diese zu erstellende Struktur.
Von der Methode wird dann ein Verwalter vom gleichen Typ der Strukturverwalter Klasse zurück geliefert.
Es ist somit quasi ein CREATE OBJECT was da im Hintergrund abläuft.
Wir haben also eine Objektinstanz zurück bekommen. Diese Objektinstanz ist noch nicht die Struktur selber, sondern nur eine Objektvariable welche auf die Strukturverwalter Klasse referenziert.
Um nun eine Strukturvariable anzulegen bzw. zu erhalten, muss der Befehl CREATE DATA abgesetzt werden.
Allerdings haben wird ja keinen Typ dieser neu zu erstellenden Struktur, sondern nur die Objektvariable des Verwalters. Daher versetzen wir nun den Befehl nicht mit TYP = xxx sondern mit dem Schlüsselwort HANDLE
Und dem verweis auf unsere objektvariable.

DATA:
lop_strucdescr TYPE REF TO CL_ABAP_STRUCTDESCR ( LOP = Lokalter Objekt Pointer )
Ldp_dynaic_record TYPE REF TO DATA ( LDP = Lokaler Daten Pointer )
Create data Ldp_dynaic_record type handle lop_strucdescr.

Nun haben wir einen Zeiger bzw. Pointer auf unsere neue Struktur. Es ist wichtig zu wissen, das es nicht die Struktur selber ist, sondern nur ein Zeiger. Der Inhalt eines solchen Zeigers ist das was uns interessiert.
Bei dem Zeiger selber, handelt es sich nur um eine Hauptspeicheradresse. Unter dieser Adresse sind dann die Daten zu finden die wir benötigen.
Deshalb wird auch mit dem Befehl:
ASSIGN lop_strucdescr->* TO <FIELD-SYMBOL> der Inhalt dieses Zeigers dem Feldsymbol zugewiesen-
Hierbei ist es wichtig zu wissen, das es oft Unfug ist, eine Zeigervariable an einem CHANGING Parameter zu übergeben. Da durch den CHANGING Parameter nicht nur der Inhalt des Zeigers, sondern auch der Zeiger selber geändert werden kann. Und somit u.U. Daten verloren gehen können. Sicherlich gibt es hier Situationen wo es durchaus Sinnvoll ist eine Objektvariable an einen CHANGING Parameter zu übergeben. Man muss sich halt darüber im klaren sein was benötigt wird.
Eine im USING Parameter übergebene Objektvariable kann durchaus ohne Schwierigkeiten innerhalb des gerufenen Bausteins den Dateninhalt verändert bekommen und an den Aufrufer zurück gegeben werden.
Hier sagt der USING Parameter nur, das die Objektvariable selber nicht geändert werden kann. Der Inhalt dieser Objektvariablen hat jedoch zunächst einmal nicht mit dem Inhalt zu tun.
Dies ist auch kein Fehler der SAP oder ähnliches, sondern eine Technik welche man verstehen muss.

Da nun unsere Struktur mittels CREATE DATA angelegt ist, benötigen wir noch eine Tabelle dafür.
Hierzu gibt es eine Tabellenverwalter Klasse mit dem Namen: CL_ABAP_TABLEDESCR
Dieser Tabellenverwalter bietet mit seiner öffentlichen Methode CREATE die Möglichkeit eine Objektvariable von genau dieser Klasse zu erstellen. Allerdings muss die CREATE Methode wissen, für welches Strukturobjekt nun ein Tabellenverwaltungsobjekt benötigt wird.

DATA:
Lop_Tab_Descr type ref to cl_abap_tabledescr

lop_tabledescr ?= cl_abap_tabledescr=>create( p_line_type = lop_strucdescr ).

Nachdem wir nun ein Tabellenverwaltungsobjekt haben, geht es analog der Erstellung der Strukturvariablen weiter,
DATA
Ldp_Dyn_Table type ref to data.

Create data Ldp_dynaic_Table type handle lop_Tab_descr.

Ich hoffe das ich mit meinen Ausführungen ein paar Kollegen helfen kann. Da auch mir über diese Foren immer sehr viel gegeben wurde, wollte ich nun einmal einen kleinen teil meiner Schuld abtragen.


Viele Grüße
Uwe
PS. Und nun das lauffähige Coding


REPORT ZZUR_DYNAMISCHE_TABELLE.
TYPE-POOLS: ABAP.

DATA:
Ldp_Dyn_Table type ref to data,
Lop_Tabledescr type ref to cl_abap_tabledescr,
Ldp_dynaic_record type ref to Data,
lop_strucdescr TYPE REF TO cl_abap_structdescr,
LS_Component TYPE abap_componentdescr,
LT_Component TYPE abap_component_tab.

Field-symbols:
<dyn_Field> TYPE any,
<Dyn_Rec> type any,
<Dyn_Tab> Type any table.


LS_Component-Name = 'NAME'.
LS_Component-TYPE = CL_ABAP_ELEMDESCR=>Get_C( P_LENGTH = 8 ).
APPEND LS_Component TO LT_Component.

LS_Component-Name = 'NUMMER'.
LS_Component-TYPE = CL_ABAP_ELEMDESCR=>Get_N( P_LENGTH = 8 ).
APPEND LS_Component TO LT_Component.

LS_Component-Name = 'PREIS'.
LS_Component-TYPE = CL_ABAP_ELEMDESCR=>Get_P( P_LENGTH = 13 P_DECIMALS = 2 ).
APPEND LS_Component TO LT_Component.

LS_Component-Name = 'ZAHL'.
LS_Component-TYPE = CL_ABAP_ELEMDESCR=>Get_I( ).
APPEND LS_Component TO LT_Component.


lop_strucdescr = cl_abap_structdescr=>create( lt_component ).

Create data Ldp_dynaic_record type handle lop_strucdescr.
Lop_Tabledescr ?= cl_abap_tabledescr=>create( p_line_type = lop_strucdescr ).


Create data Ldp_Dyn_Table type handle Lop_Tabledescr.

ASSIGN Ldp_dynaic_record->* to <Dyn_Rec>.
ASSIGN Ldp_Dyn_Table->* to <Dyn_Tab>.


ASSIGN COMPONENT 'NAME' OF STRUCTURE <Dyn_Rec> TO <dyn_Field>.
<dyn_Field> = 'Hugo'.
UNASSIGN <dyn_Field>.


ASSIGN COMPONENT 'NUMMER' OF STRUCTURE <Dyn_Rec> TO <dyn_Field>.
<dyn_Field> = '4711'.
UNASSIGN <dyn_Field>.


ASSIGN COMPONENT 'ZAHL' OF STRUCTURE <Dyn_Rec> TO <dyn_Field>.
<dyn_Field> = '1'.
UNASSIGN <dyn_Field>.


ASSIGN COMPONENT 'PREIS' OF STRUCTURE <Dyn_Rec> TO <dyn_Field>.
<dyn_Field> = '23.85'.
UNASSIGN <dyn_Field>.

INSERT <Dyn_Rec> INTO TABLE <Dyn_tab>.

DATA:
lv_idx TYPE i.
Loop at <Dyn_tab> into <Dyn_Rec>.
Sy-SubRC = 0.
lv_idx = 0.
WHILE Sy-SubRC = 0.
add 1 to lv_idx.
ASSIGN COMPONENT lv_idx OF STRUCTURE <Dyn_Rec> TO <dyn_Field>.
CHECK Sy-SubRC = 0.
WRITE: / <dyn_Field>.
UNASSIGN <dyn_Field>.
ENDWHILE.
Endloop.

Folgende Benutzer bedankten sich beim Autor Uwe.Rimarski für den Beitrag:
Tron



Re: Dynamische Tabellenstrukturen im ABAP

Beitrag von LAT (ForumUser / 1 / 0 / 0 ) »
Vielen Dank. Vor allem die Erklärungen haben mir geholfen. Ich habe das schon öfter probiert und mit durchgewurschtelt bis es ging. Verstanden warum hatte ich dabei nicht.

Seite 1 von 1

Über diesen Beitrag


Unterstütze die Community und teile den Beitrag für mehr Leser und besseren Inhalt:

Vergleichbare Themen

Zuweisung von Tabellenstrukturen
von av_deh » 14.04.2011 11:59
dynamische Wertehilfe in Adobe forms (Web Dynpro ABAP)
von Jan-Ole » 16.01.2006 16:31
Kundeneigene ABAP-Muster Vorlage im ABAP-Editor anlegen
von Stentor » 19.07.2005 11:10
Dynamische SQL
von Gabriel99 » 22.06.2015 17:59
Dynamische Typisierung?
von cortex » 18.03.2014 09:10