最近接了一个需要将XML转换为ABAP内表的开发需求。目前已经将XML的内容读进内存了,但是因为XML嵌套的结构太多也太深,所以常用的通过字段目录创建动态结构的方法无法满足业务需求。所以通过向同事打听与查阅资料,发现了SAP关于RTTC创建动态结构的内容可以满足很深层次的动态结构创建。
现已将其封装成一个工具Function,通过输入想要创建的动态结构内容,然后就可以拿到一个引用类型的对象。
RTTS动态结构创建
一、运行时类型服务(RTTS) 1.介绍 RTTS是使用类型描述类 的层次结构实现的,这些类别包含运行时类型创建(RTTC) 和运行时类型标识(RTTI) 的方法。使用这些标准类可以在运行时动态创建ABAP中的结构。
通过在运行时设置由标准类提供的CL_ABAP_STRUCTDESCR=>COMPONENT_TABLE 类型的内表内容,然后使用该内表创建新的结构体对象/内表对象。之后在CREATE DATA 语句中在TYPE 关键词之后使用HANDLE 指定新的结构体对象/内表对象后就可以拿到这些新对象的应用变量进行操作了。
上面的内容不明白可以继续往后看,看过实例之后就会有比较清晰的认识了。
2.标准类的层次结构
我们主要使用到的类就是上面的内容。通过类的名称与描述信息可以确定自己创建动态结构时需要使用到的具体是哪一个标准类。
类名
作用
CL_ABAP_TYPEDESCR
动态类型类。
CL_ABAP_DATADESCR
变量生成类 ,可以将由其子类生成的对象传递给该类的对象。然后引用变量直接参照该类的对象创建对象。
CL_ABAP_ELEMDESCR
数据元素生成类 ,可以根据数据元素生成对象,也可以根据基本数据类型生成变量。
CL_ABAP_ENUMDESCR
枚举类型生成类。
CL_ABAP_REFDESCR
引用类型生成类 ,可以生成引用类型变量。
CL_ABAP_COMPLEXDESCR
组件生成类 ,一般不会使用该类生成对象,而是使用它的两个子类来生成结构体与内表对象。
CL_ABAP_STRUCTDESCR
结构体生成类 ,可以根据上面提到的该类COMPONENT_TABLE 类型的变量动态生成结构体对象。
CL_ABAP_TABLEDESCR
内表生成类 ,需要和上面的结构体生成类对象一起使用,由结构体生成类对象确定内表的结构,然后再根据内表生成类中的其余属性来确定需要生成的内表是什么类型(标准、排序…)的与主键信息等。
CL_ABAP_OBJECTDESCR
对象生成父类 ,用于生成Object对象的类,主要使用的也是其两个子类来生成对象。
CL_ABAP_CLASSDESCR
类生成对象类 ,通过传入的自定义类内容来定义和生成对象。
CL_ABAP_INTFDESCR
接口生成队形类 ,和上面根据类生成对象类似,通过传入自定义的接口内容,创建对象。
二、动态对象生成的核心逻辑 1.根据DDIC结构生成内表 (1)说明 直接参照DDIC结构生成结构体或内表对象。DDIC结构一般指在SE11中定义的结构、数据库表等对象。
(2)实例 参照航班表 SFLIGHT 创建内表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 TRY. "将DDIC的结构名称传入结构体定义对象 DATA(LO_STRUCT_DESC) = CL_ABAP_STRUCTDESCR=>DESCRIBE_BY_NAME( 'SFLIGHT' ). "根据上面的结构体对象创建内表对象 DATA(LO_TABLE_DESC) = CL_ABAP_TABLEDESCR=>CREATE( P_LINE_TYPE = CAST #( LO_STRUCT_DESC ) "内表的结构 P_TABLE_KIND = CL_ABAP_TABLEDESCR=>TABLEKIND_STD "内表类型 P_UNIQUE = ABAP_FALSE ). "使用引用变量创建内表对象 DATA LO_TABLE TYPE REF TO DATA. CREATE DATA LO_TABLE TYPE HANDLE LO_TABLE_DESC. "请注意此处必须在TYPE关键词后使用HANDLE关键词 "使用指针指向生成的内表 FIELD-SYMBOLS <FT_TABLE> TYPE ANY TABLE. ASSIGN LO_TABLE->* TO <FT_TABLE>. CATCH CX_ROOT INTO DATA(LO_ERROR). DATA(LV_MESSAGE) = LO_ERROR->GET_TEXT( ). ENDTRY.
生成的内表结构与DDIC对应的航班表SFLIGHT结构一致。
2.动态组件生成内表 (1)说明 接下来的这种方式是在运行时通过传入cl_abap_structdescr=>component_table 类型内表中的字段名、字段类型等信息去动态生成内表对象的。字段类型可以是基本数据类型 ,也可以是数据元素 和CL_ABAP_COMPLEXDESCR与其子类对象 。设置完成该内表值后再使用**cl_abap_structdescr=>create( )**方法根据内表值生成结构体对象。有了结构体对象之后创建内表的方法就和上面一样了。
(2)实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 TRY. DATA LV_FLDATE TYPE SFLIGHT-FLDATE. "填充动态组件的属性内表 DATA(LT_COMPONENTS) = VALUE CL_ABAP_STRUCTDESCR=>COMPONENT_TABLE( "创建一个字段名为CARRID,类型为C类型长度为3位的字段 ( NAME = 'CARRID' TYPE = CL_ABAP_ELEMDESCR=>GET_C( 3 ) ) "创建一个字段名为CONNID,类型为N类型长度为4位的字段 ( NAME = 'CONNID' TYPE = CL_ABAP_ELEMDESCR=>GET_N( 4 ) ) "创建一个字段名为CARRNAME,类型参照数据元素S_CARRNAME的字段 ( NAME = 'CARRNAME' TYPE = CAST #( CL_ABAP_ELEMDESCR=>DESCRIBE_BY_NAME( 'S_CARRNAME' ) ) ) "创建一个字段名为FLDATE,类型参照程序已有变量LV_FLDATE的字段 ( NAME = 'FLDATE' TYPE = CAST #( CL_ABAP_ELEMDESCR=>DESCRIBE_BY_DATA( LV_FLDATE ) ) ) ). "根据动态组件内表生成结构体对象 DATA(LO_STRUCT_DESC) = CL_ABAP_STRUCTDESCR=>CREATE( LT_COMPONENTS ). "根据上面的结构体对象创建内表对象 DATA(LO_TABLE_DESC) = CL_ABAP_TABLEDESCR=>CREATE( P_LINE_TYPE = CAST #( LO_STRUCT_DESC ) "内表的结构 P_TABLE_KIND = CL_ABAP_TABLEDESCR=>TABLEKIND_STD "内表类型 P_UNIQUE = ABAP_FALSE P_KEY = VALUE #( ( NAME = 'CARRID' ) ( NAME = 'CONNID' ) ) P_KEY_KIND = CL_ABAP_TABLEDESCR=>KEYDEFKIND_USER ). "使用引用变量创建内表对象 DATA LO_TABLE TYPE REF TO DATA. CREATE DATA LO_TABLE TYPE HANDLE LO_TABLE_DESC. "请注意此处必须在TYPE关键词后使用HANDLE关键词 "使用指针指向生成的内表 FIELD-SYMBOLS <FT_TABLE> TYPE ANY TABLE. ASSIGN LO_TABLE->* TO <FT_TABLE>. CATCH CX_ROOT INTO DATA(LO_ERROR). DATA(LV_MESSAGE) = LO_ERROR->GET_TEXT( ). ENDTRY.
可以看到根据已有变量创建的字段类型会和变量的类型保持一致。变量LV_FLDATE的类型是日期类型的,所以参照该变量定义的字段也是日期类型的。
三、动态生成组件工具函数 1.程序源码 (1)函数源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 *"---------------------------------------------------------------------- *"*"本地接口: *" EXPORTING *" REFERENCE(ER_REF) TYPE REF TO DATA *" REFERENCE(EV_MESSAGE) TYPE STRING *" TABLES *" IT_DEFINITION TYPE ZTT_TYPE_DEFINITION *" EXCEPTIONS *" INPUT_TABLE_EMPTY *" INPUT_TABLE_DATA_EXCEPTION *" INPUT_TABLE_FIELDNAME_EMPTY *" STRUCTURAL_HIERARCHY_ANOMALIES *"---------------------------------------------------------------------- *--------------------------Variables-----------------------------------* DATA: LV_TABIX TYPE SY-TABIX VALUE 1, "表索引 LV_KIND TYPE C, "生成对象的类型 S 结构体 T 内表 * LT_COMPONENTS TYPE ABAP_COMPONENT_TAB, LO_OBJECT TYPE REF TO CL_ABAP_DATADESCR."返回的组件对象 *----------------------------Logic-------------------------------------* "Input data non-null judgment IF IT_DEFINITION[] IS INITIAL. RAISE INPUT_TABLE_EMPTY. ENDIF. "设置对象类型 CLEAR: IT_DEFINITION. PERFORM GET_OBJECT TABLES IT_DEFINITION * LT_COMPONENTS USING IT_DEFINITION LV_KIND CHANGING LV_TABIX LO_OBJECT EV_MESSAGE. "创建参考对象 CREATE DATA ER_REF TYPE HANDLE LO_OBJECT. ASSIGN ER_REF->* TO FIELD-SYMBOL(<FO_OBJECT>).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 FORM GET_OBJECT TABLES PT_DEFINITION TYPE ZTT_TYPE_DEFINITION * PT_COMPONENTS TYPE ABAP_COMPONENT_TAB USING VALUE(PS_DEFINITION) TYPE ZTS_TYPE_DEFINITION VALUE(PV_KIND) TYPE C CHANGING VALUE(PV_TABIX) TYPE SY-TABIX VALUE(PO_OBJECT) TYPE REF TO CL_ABAP_DATADESCR VALUE(EV_MESSAGE) TYPE STRING. *--------------------------Variables-----------------------------------* CONSTANTS: LC_I TYPE C LENGTH 1 VALUE 'I', LC_F TYPE C LENGTH 1 VALUE 'F', LC_P TYPE C LENGTH 1 VALUE 'P', LC_C TYPE C LENGTH 1 VALUE 'C', LC_N TYPE C LENGTH 1 VALUE 'N', LC_D TYPE C LENGTH 1 VALUE 'D', LC_T TYPE C LENGTH 1 VALUE 'T', LC_X TYPE C LENGTH 1 VALUE 'X'. DATA: LT_KEY TYPE ABAP_KEYDESCR_TAB, LV_TYPE TYPE REF TO CL_ABAP_DATADESCR, LV_KIND TYPE C, "S 结构体 T 内表 LV_LEVEL TYPE I, LV_LENGTH TYPE I, LV_DECIMALS TYPE I, LT_COMPONENTS TYPE ABAP_COMPONENT_TAB, LO_TABLE_DESC TYPE REF TO CL_ABAP_TABLEDESCR. *----------------------------Logic-------------------------------------* TRY. "记录当前递归中的层级 LV_LEVEL = PT_DEFINITION[ PV_TABIX ]-LEVEL. "层级判断,递归中的层级只能比上一层递归的层级高 IF PS_DEFINITION-LEVEL IS NOT INITIAL AND PS_DEFINITION-LEVEL > LV_LEVEL. "当前层级不大于上层递归层级,退出本层递归 "递归层级异常,请检查动态表结构内容 EV_MESSAGE = TEXT-E01. RAISE STRUCTURAL_HIERARCHY_ANOMALIES. ENDIF. LOOP AT PT_DEFINITION FROM PV_TABIX WHERE LEVEL = LV_LEVEL. PV_TABIX = SY-TABIX. "判断是否是普通字段/结构/表类型 IF PT_DEFINITION-KIND IS INITIAL AND PT_DEFINITION-ELEMENT IS INITIAL AND PT_DEFINITION-TYPE IS INITIAL. "结构体 "设置创建的类型标识 LV_KIND = 'S'. PV_TABIX = PV_TABIX + 1. "递归调用,获取结构体对象 PERFORM GET_OBJECT TABLES PT_DEFINITION * PT_COMPONENTS USING PT_DEFINITION LV_KIND CHANGING PV_TABIX PO_OBJECT EV_MESSAGE. CHECK EV_MESSAGE IS INITIAL. "将结构对象传入内表 LV_TYPE ?= PO_OBJECT. LT_COMPONENTS = VALUE #( BASE LT_COMPONENTS ( NAME = PT_DEFINITION-FIELD TYPE = LV_TYPE ) ). ELSEIF PT_DEFINITION-KIND IS NOT INITIAL AND PT_DEFINITION-ELEMENT IS INITIAL AND PT_DEFINITION-TYPE IS INITIAL. "表类型 "判断是否是第一条数据 IF PV_TABIX = 1 AND PT_DEFINITION-FIELD IS INITIAL AND PT_DEFINITION-LEVEL = 1. DATA(LV_EXIT_FLAG) = 'X'. ENDIF. "设置创建的类型标识 LV_KIND = 'T'. PV_TABIX = PV_TABIX + 1. "递归调用,获取结构体对象 PERFORM GET_OBJECT TABLES PT_DEFINITION * PT_COMPONENTS USING PT_DEFINITION LV_KIND CHANGING PV_TABIX PO_OBJECT EV_MESSAGE. CHECK EV_MESSAGE IS INITIAL. "退出判断 IF LV_EXIT_FLAG IS NOT INITIAL. "是,则代表创建的结构一开始就是一个内表 EXIT. ELSE. "将结构对象传入内表 LV_TYPE ?= PO_OBJECT. LT_COMPONENTS = VALUE #( BASE LT_COMPONENTS ( NAME = PT_DEFINITION-FIELD TYPE = LV_TYPE ) ). ENDIF. ELSEIF PT_DEFINITION-KIND IS INITIAL AND ( PT_DEFINITION-ELEMENT IS NOT INITIAL OR PT_DEFINITION-TYPE IS NOT INITIAL ). "普通字段类型 IF PT_DEFINITION-ELEMENT IS NOT INITIAL. "参照DataElement LV_TYPE = CAST #( CL_ABAP_ELEMDESCR=>DESCRIBE_BY_NAME( PT_DEFINITION-ELEMENT ) ). ELSE. "基本数据类型 LV_LENGTH = PT_DEFINITION-LENG. LV_DECIMALS = PT_DEFINITION-DECIMALS. CASE PT_DEFINITION-TYPE. WHEN LC_I. LV_TYPE = CAST #( CL_ABAP_ELEMDESCR=>GET_I( ) ). WHEN LC_F. LV_TYPE = CAST #( CL_ABAP_ELEMDESCR=>GET_F( ) ). WHEN LC_P. LV_TYPE = CAST #( CL_ABAP_ELEMDESCR=>GET_P( P_LENGTH = LV_LENGTH P_DECIMALS = LV_DECIMALS ) ). WHEN LC_C. LV_TYPE = CAST #( CL_ABAP_ELEMDESCR=>GET_C( P_LENGTH = LV_LENGTH ) ). WHEN LC_N. LV_TYPE = CAST #( CL_ABAP_ELEMDESCR=>GET_N( P_LENGTH = LV_LENGTH ) ). WHEN LC_D. LV_TYPE = CAST #( CL_ABAP_ELEMDESCR=>GET_D( ) ). WHEN LC_T. LV_TYPE = CAST #( CL_ABAP_ELEMDESCR=>GET_T( ) ). WHEN LC_X. LV_TYPE = CAST #( CL_ABAP_ELEMDESCR=>GET_X( P_LENGTH = LV_LENGTH ) ). WHEN OTHERS. ENDCASE. ENDIF. IF PT_DEFINITION-KEY IS NOT INITIAL. LT_KEY = VALUE #( BASE LT_KEY ( NAME = PT_DEFINITION-FIELD ) ). ENDIF. LT_COMPONENTS = VALUE #( BASE LT_COMPONENTS ( NAME = PT_DEFINITION-FIELD TYPE = LV_TYPE ) ). ENDIF. "判断当前层级是否大于下一层级 IF PV_TABIX < LINES( PT_DEFINITION ). IF LV_LEVEL > PT_DEFINITION[ PV_TABIX + 1 ]-LEVEL. "当前结构的层级已结束 EXIT. ENDIF. ENDIF. CLEAR: PT_DEFINITION. ENDLOOP. "根据判断创建对应的对象 IF LT_COMPONENTS IS NOT INITIAL. CASE PV_KIND. WHEN 'S'. DATA(LO_STRUCT_DESC) = CL_ABAP_STRUCTDESCR=>CREATE( LT_COMPONENTS ). WHEN 'T'. LO_STRUCT_DESC = CL_ABAP_STRUCTDESCR=>CREATE( LT_COMPONENTS ). LO_TABLE_DESC = CL_ABAP_TABLEDESCR=>CREATE( P_LINE_TYPE = LO_STRUCT_DESC P_TABLE_KIND = PS_DEFINITION-KIND P_UNIQUE = ABAP_FALSE P_KEY = LT_KEY P_KEY_KIND = COND #( WHEN PS_DEFINITION-KEY_KIND IS INITIAL THEN CL_ABAP_TABLEDESCR=>KEYDEFKIND_DEFAULT ELSE PS_DEFINITION-KEY_KIND ) ). WHEN OTHERS. LO_STRUCT_DESC = CL_ABAP_STRUCTDESCR=>CREATE( LT_COMPONENTS ). ENDCASE. ENDIF. "将对象返回 IF LO_TABLE_DESC IS BOUND. PO_OBJECT ?= LO_TABLE_DESC. ELSEIF LO_STRUCT_DESC IS BOUND. PO_OBJECT ?= LO_STRUCT_DESC. ENDIF. MOVE-CORRESPONDING PS_DEFINITION TO PT_DEFINITION. CATCH CX_ROOT INTO DATA(LO_ERROR). EV_MESSAGE = LO_ERROR->GET_TEXT( ). ENDTRY. FREE: LT_KEY,LT_COMPONENTS. ENDFORM.
(2)传入参数结构 ZTT_TYPE_DEFINITION 为表类型,其参照的结构为ZTS_TYPE_DEFINITION 。
下面是参数的说明与参考值信息。
字段名
描述
参考值
参考值说明/备注
LEVEL
层级
若是简单无嵌套动态结构可不输入
FIELD
字段名称
动态组件的字段名
KEY
关键标识字段
内表中的主键标记字段,主要在排序表中使用
KEY_KIND
关键字段类型
和上面的类型一起使用,关键字段的类型
CL_ABAP_TABLEDESCR=>KEYDEFKIND_DEFAULT
默认类型
CL_ABAP_TABLEDESCR=>KEYDEFKIND_TABLELINE
表主键(一般用于从DDIC创建内表主字段使用)
CL_ABAP_TABLEDESCR=>KEYDEFKIND_TABLELINE
用户自定义键
CL_ABAP_TABLEDESCR=>KEYDEFKIND_EMPTY
用户自定义键
KIND
表类型
CL_ABAP_TABLEDESCR=>TABLEKIND_ANY
泛型表
CL_ABAP_TABLEDESCR=>TABLEKIND_STD
标准表
CL_ABAP_TABLEDESCR=>TABLEKIND_INDEX
索引表
CL_ABAP_TABLEDESCR=>TABLEKIND_HASHED
Hash表
CL_ABAP_TABLEDESCR=>TABLEKIND_SORTED
排序表
ELEMENT
数据元素 (语义域)
和下面的TYPE、LENG与DECIMALS类似,都是用来控制字段类型的,但是填写了数据元素后下面的TYPE、LENG与DECIMALS就可以不用填写了,反之填写了TYPE、LENG与DECIMALS就可以不用填写ELEMENT了。
TYPE
ABAP 数据类型(C,D,N,…)
基本数据类型,I、F、P、C、N、D、T和X
LENG
长度(字符数)
变量的长度,只有P、C、N与X类型需要填写
DECIMALS
小数位数
小数位长度,只有P类型需要填写
PARENT
父层级 (暂未使用)
暂未使用到,可以不用添加该字段
2.程序说明 该函数主要是适用于上面动态组件生成对象的逻辑。即填充cl_abap_structdescr=>component_table 类型的内表然后创建结构体与内表对象。暂时未添加根据DDIC结构创建动态结构的功能,因为直接根据DDIC结构创建动态结构的方法很多。
该函数主要是用来动态创建发杂的/深层级的组件对象的。例如结构体嵌套结构体/内表、内表嵌套结构体/内表,然后他们嵌套的子结构还可以继续嵌套更深层级的组件对象时,可以使用该工具函数创建这些组件对象。
3.使用说明 (1)结构体创建 ① 输入参数参考 如果要创建一个结构体,只需要将结构体中字段名称和字段类型填写上即可。
LEVEL
FIELD
KEY
KEY_KIND
KIND
ELEMENT
TYPE
LENG
DECIMALS
1
FIELD1
CHAR10
1
FIELD2
C
10
1
FIELD3
P
10
2
② 程序执行结果
(2)内表创建 ① 输入参数参考 创建内表时,在输入参数的第一条数据中写上层级与表类型即可,然后在第二行写上表字段的名称层级与类型信息。KIND为S代表标准表,在上面的参考值中对应CL_ABAP_TABLEDESCR=>TABLEKIND_STD 。
LEVEL
FIELD
KEY
KEY_KIND
KIND
ELEMENT
TYPE
LENG
DECIMALS
1
S
2
FIELD1
C
10
2
FIELD2
P
10
2
2
FIELD3
SYDATUM
② 程序执行结果
(3)复杂结构-结构体嵌套结构体/内表 如果涉及到深层的例如结构体嵌套结构体/内表的情况,则按照下面的方式进行即可。同理如果已经嵌套的组件对象中还有更深层次的组件对象,则可以根据他们在嵌套组件中的位置和层级关系继续嵌套。
① 输入参数参考
LEVEL
FIELD
KEY
KEY_KIND
KIND
ELEMENT
TYPE
LENG
DECIMALS
1
FIELD1
CHAR10
1
FIELD2
C
10
1
FIELD3
P
10
2
1
STRUCTURE1
2
STRFIELD1
CHAR10
2
STRFIELD2
CHAR10
2
STRFIELD3
CHAR10
2
STRUCTURE2
3
STRFIELD2_1
CHAR10
3
STRFIELD2_2
CHAR10
1
TABLE
S
2
TABFIELD1
CHAR10
2
TABFIELD2
CHAR10
2
TABFIELD3
CHAR10
② 程序执行结果
(4)复杂结构-内表嵌套结构体/内表 在外层的内表中嵌套了结构体STRUCTURE之后,有嵌套了内表TABLE1。在TABLE1内部又再次嵌套了TABLE2.
① 输入参数参考
LEVEL
FIELD
KEY
KEY_KIND
KIND
ELEMENT
TYPE
LENG
DECIMALS
1
S
2
FIELD1
CHAR10
2
FIELD2
C
10
2
FIELD3
P
10
2
2
STRUCTURE
3
STRFIELD1
CHAR10
3
STRFIELD2
CHAR10
2
FIELD4
2
TABLE1
S
3
TAB1FIELD1
CHAR10
3
TAB1FIELD2
CHAR10
3
TAB1FIELD3
CHAR10
3
TABLE2
S
4
TAB2FIELD1
CHAR10
4
TAB2FIELD2
CHAR10
3
TAB1FIELD4
CHAR10
② 程序执行结果 通过断点调试新增一行初始值可以看的更直观一些。
返回的第一层内表结构图下所示。
第一层内表中的STRUCTURE 结构如下图所示。
第一层内表中的TABLE1 结构如下图所示。
第二层内表中的TABLE2 结构如下图所示。
可以看到创建出来的复杂结构对象满足一开始设计的内容。
四、参考资料 How To Create A Dynamic Internal Table Using RTTS
Runtime Type Services (RTTS)