ABAP2XML

写接口用到XML,但又不想每次写STRANS,在网页和github都没找到合适的(可能也有但是我没找到)

参考:https://blogs.sap.com/2014/08/01/abap-to-xml-and-vice-versa/

这个人写的ABAP2XML可以用,但是有个缺点,当节点是表类型的时候,会同时定义一个table节点<sflight>和structure节点<sflight>。所以我对它的代码改了一下,如果有BUG或者问题,还请评论告诉我

 

 

 

这里有个问题,虽然mo_document->set_encoding设置的是 'UTF-8',得到的ev_content都是'UTF-16',

但是把xstring或者binary下载到本地.xml文件,显示的是对的'UTF-8'。所以我理解为if_ixml_element生成的XML的STRING类型默认显示'UTF-16',就给REPLACE替换了一下。

 

 

 

完整代码如下,SE24粘贴即可

  1 class ZCL_XML_UTIL definition
  2   public
  3   create public .
  4 
  5 public section.
  6 
  7 *”* public components of class ZCL_XML_UTIL
  8 *”* do not include other source files here!!!
  9   methods CONSTRUCTOR .
 10   methods ABAP_TO_XML
 11     importing
 12       !IM_DATA type ANY
 13     exporting
 14       !EX_CONTENT type XSTRING
 15       !EV_CONTENT type STRING .
 16   methods XML_TO_ABAP
 17     importing
 18       !IM_CONTENT type STRING optional
 19       !IM_CONTENT_X type XSTRING optional
 20     exporting
 21       !EX_DATA type ANY .
 22 protected section.
 23 *”* protected components of class ZCL_XML_UTIL
 24 *”* do not include other source files here!!!
 25 
 26   data MO_IXML type ref to IF_IXML .
 27   data MO_DOCUMENT type ref to IF_IXML_DOCUMENT .
 28 private section.
 29 
 30 *”* private components of class ZCL_XML_UTIL
 31 *”* do not include other source files here!!!
 32   methods PROCESS
 33     importing
 34       !IM_NODE type ref to IF_IXML_NODE
 35       !IM_NAME type STRING
 36       !IM_DATA type ANY
 37     exceptions
 38       TYPE_ERROR .
 39   methods CREATE_ELEMENT
 40     importing
 41       !IM_NAME type STRING
 42       !IM_VALUE type STRING optional
 43     returning
 44       value(RE_ELEMENT) type ref to IF_IXML_ELEMENT .
 45   methods TRAVERSE
 46     importing
 47       !IM_CURRENT_NODE type ref to IF_IXML_NODE
 48     changing
 49       !CH_DATA type ANY
 50     exceptions
 51       TYPE_NOT_FOUND .
 52   class-methods AS_STRING
 53     importing
 54       !IM_DATA type ANY
 55     returning
 56       value(RE_DATA_STRING) type STRING .
 57 ENDCLASS.
 58 
 59 
 60 
 61 CLASS ZCL_XML_UTIL IMPLEMENTATION.
 62 
 63 
 64 * <SIGNATURE>---------------------------------------------------------------------------------------+
 65 * | Instance Public Method ZCL_XML_UTIL->ABAP_TO_XML
 66 * +-------------------------------------------------------------------------------------------------+
 67 * | [--->] IM_DATA                        TYPE        ANY
 68 * | [<---] EX_CONTENT                     TYPE        XSTRING
 69 * | [<---] EV_CONTENT                     TYPE        STRING
 70 * +--------------------------------------------------------------------------------------</SIGNATURE>
 71 METHOD abap_to_xml.
 72 
 73   CLEAR : ex_content.
 74 
 75 * create .xml document
 76   mo_document = mo_ixml->create_document( ).
 77 
 78 * set encoding to UTF-8 (Unicode Transformation Format)
 79 * 8-bit variable-width encoding maximizes compatibility with ASCII
 80   mo_document->set_encoding( mo_ixml->create_encoding(
 81       byte_order    = 0
 82       character_set = 'UTF-8' ) ).
 83 
 84 
 85 *   use mo_document as root
 86   IF NOT im_data IS INITIAL.
 87     process( im_node = mo_document
 88              im_name = 'docinfo'
 89              im_data = im_data ).
 90   ENDIF.
 91 
 92 
 93 * render .xml document with output stream
 94 *--------------------------------------------------------------------*
 95 *xstring
 96   mo_document->render(
 97     ostream = mo_ixml->create_stream_factory( )->create_ostream_xstring(
 98       string = ex_content ) ).
 99 
100 *--------------------------------------------------------------------*
101 *string
102   mo_document->render(
103     ostream = mo_ixml->create_stream_factory( )->create_ostream_cstring(
104       string = ev_content ) ).
105   REPLACE 'encoding="utf-16"' WITH 'encoding="utf-8"' INTO ev_content.  "实质以create_encoding为准
106 
107 *--------------------------------------------------------------------*
108 *itable
109 *  TYPES: BEGIN OF xml_line,
110 *           data(256) TYPE x,   "这里的长度设置不会影响输出结果
111 *         END OF xml_line.
112 *  DATA:et_content TYPE TABLE OF xml_line.
113 *  data(l_ostream) = mo_ixml->create_stream_factory( )->create_ostream_itable(
114 *      table    = et_content  ).
115 *  mo_document->render( l_ostream ).
116 *  data(xml_size) = l_ostream->get_num_written_raw( )."取得XML数据大小
117 
118 
119   FREE : mo_document.
120 ENDMETHOD.
121 
122 
123 * <SIGNATURE>---------------------------------------------------------------------------------------+
124 * | Static Private Method ZCL_XML_UTIL=>AS_STRING
125 * +-------------------------------------------------------------------------------------------------+
126 * | [--->] IM_DATA                        TYPE        ANY
127 * | [<-()] RE_DATA_STRING                 TYPE        STRING
128 * +--------------------------------------------------------------------------------------</SIGNATURE>
129 METHOD AS_STRING.
130 
131   MOVE im_data TO re_data_string.
132 
133 ENDMETHOD.
134 
135 
136 * <SIGNATURE>---------------------------------------------------------------------------------------+
137 * | Instance Public Method ZCL_XML_UTIL->CONSTRUCTOR
138 * +-------------------------------------------------------------------------------------------------+
139 * +--------------------------------------------------------------------------------------</SIGNATURE>
140 METHOD CONSTRUCTOR.
141 
142 * get iXML library instance
143   mo_ixml = cl_ixml=>create( ).
144 
145 ENDMETHOD.
146 
147 
148 * <SIGNATURE>---------------------------------------------------------------------------------------+
149 * | Instance Private Method ZCL_XML_UTIL->CREATE_ELEMENT
150 * +-------------------------------------------------------------------------------------------------+
151 * | [--->] IM_NAME                        TYPE        STRING
152 * | [--->] IM_VALUE                       TYPE        STRING(optional)
153 * | [<-()] RE_ELEMENT                     TYPE REF TO IF_IXML_ELEMENT
154 * +--------------------------------------------------------------------------------------</SIGNATURE>
155 METHOD CREATE_ELEMENT.
156 
157   DATA :
158     lv_name TYPE string VALUE IS INITIAL.
159 
160 * element names look cooler in lower case 🙂
161   lv_name = to_lower( im_name ).
162 
163 * create element with given name
164   re_element = mo_document->create_element( name = lv_name ).
165 
166 * if element is leaf, set corresponding value
167   IF im_value IS NOT INITIAL.
168     re_element->set_value( im_value ).
169   ENDIF.
170 
171 ENDMETHOD.
172 
173 
174 * <SIGNATURE>---------------------------------------------------------------------------------------+
175 * | Instance Private Method ZCL_XML_UTIL->PROCESS
176 * +-------------------------------------------------------------------------------------------------+
177 * | [--->] IM_NODE                        TYPE REF TO IF_IXML_NODE
178 * | [--->] IM_NAME                        TYPE        STRING
179 * | [--->] IM_DATA                        TYPE        ANY
180 * | [EXC!] TYPE_ERROR
181 * +--------------------------------------------------------------------------------------</SIGNATURE>
182 METHOD process.
183 
184   DATA :
185     lo_type    TYPE REF TO cl_abap_typedescr,
186     lo_struct  TYPE REF TO cl_abap_structdescr,
187     lo_table   TYPE REF TO cl_abap_tabledescr,
188     lo_data    TYPE REF TO data,
189     lo_element TYPE REF TO if_ixml_element,
190     lv_name    TYPE string VALUE IS INITIAL.
191 
192   FIELD-SYMBOLS :
193     <ft_data>      TYPE STANDARD TABLE,
194     <fs_component> TYPE abap_compdescr,
195     <fs_data>      TYPE any,
196     <fv_value>     TYPE any.
197 
198 * determine ABAP/4 data type, support only:
199 * - simple type
200 * - structure
201 * - table type
202   lo_type = cl_abap_typedescr=>describe_by_data( im_data ).
203 
204   CASE lo_type->kind.
205     WHEN cl_abap_typedescr=>kind_elem.
206 *     create element
207       lo_element = create_element(
208           im_name  = im_name
209           im_value = as_string( im_data ) ).
210 
211       IF lo_element IS BOUND.
212         im_node->append_child( lo_element ).
213       ENDIF.
214 
215     WHEN cl_abap_typedescr=>kind_struct.
216 *     create parent element
217       lo_element = create_element( im_name = im_name ).
218 
219 *     process each structure component independently
220       lo_struct ?= cl_abap_structdescr=>describe_by_data( im_data ).
221       LOOP AT lo_struct->components ASSIGNING <fs_component>.
222         ASSIGN COMPONENT <fs_component>-name OF STRUCTURE im_data TO <fv_value>.
223         CHECK sy-subrc IS INITIAL.
224 
225         lv_name = <fs_component>-name.
226 
227         process( im_node = lo_element
228                  im_name = lv_name
229                  im_data = <fv_value> ).
230 
231       ENDLOOP.
232 
233       IF lo_element IS BOUND.
234         im_node->append_child( lo_element ).
235       ENDIF.
236 
237     WHEN cl_abap_typedescr=>kind_table.
238       ASSIGN im_data TO <ft_data>.
239 
240       LOOP AT <ft_data> ASSIGNING <fs_data>.
241 *     create parent element
242         lo_element = create_element( im_name = im_name ).
243 
244 *     process each structure component independently
245         lo_struct ?= cl_abap_structdescr=>describe_by_data( <fs_data> ).
246         LOOP AT lo_struct->components ASSIGNING <fs_component>.
247           ASSIGN COMPONENT <fs_component>-name OF STRUCTURE <fs_data> TO <fv_value>.
248           CHECK sy-subrc IS INITIAL.
249 
250           lv_name = <fs_component>-name.
251 
252           process( im_node = lo_element
253                    im_name = lv_name
254                    im_data = <fv_value> ).
255         ENDLOOP.
256 
257         IF lo_element IS BOUND.
258           im_node->append_child( lo_element ).
259           free lo_element.
260         ENDIF.
261 
262       ENDLOOP.
263 
264     WHEN OTHERS.
265       TRY.
266           RAISE type_error.
267       ENDTRY.
268   ENDCASE.
269 
270 
271 
272 *--------------------------------------------------------------------*
273 *  "Must Import Structure Of Level1 Data
274 *--------------------------------------------------------------------*
275 *METHOD process.
276 *
277 *  DATA :
278 *    lo_type    TYPE REF TO cl_abap_typedescr,
279 *    lo_struct  TYPE REF TO cl_abap_structdescr,
280 *    lo_table   TYPE REF TO cl_abap_tabledescr,
281 *    lo_data    TYPE REF TO data,
282 *    lo_element TYPE REF TO if_ixml_element,
283 *    lv_name    TYPE string VALUE IS INITIAL.
284 *
285 *  FIELD-SYMBOLS :
286 *    <ft_data>      TYPE STANDARD TABLE,
287 *    <fs_component> TYPE abap_compdescr,
288 *    <fs_data>      TYPE any,
289 *    <fv_value>     TYPE any.
290 *
291 ** determine ABAP/4 data type, support only:
292 ** - simple type
293 ** - structure
294 ** - table type
295 *  lo_type = cl_abap_typedescr=>describe_by_data( im_data ).
296 *
297 *  CASE lo_type->kind.
298 *    WHEN cl_abap_typedescr=>kind_elem.
299 **     create element
300 *      lo_element = create_element(
301 *          im_name  = im_name
302 *          im_value = as_string( im_data ) ).
303 *
304 *    WHEN cl_abap_typedescr=>kind_struct.
305 **     create parent element
306 *      lo_element = create_element( im_name = im_name ).
307 *
308 **     process each structure component independently
309 *      lo_struct ?= cl_abap_structdescr=>describe_by_data( im_data ).
310 *      LOOP AT lo_struct->components ASSIGNING <fs_component>.
311 *        ASSIGN COMPONENT <fs_component>-name OF STRUCTURE im_data TO <fv_value>.
312 *        CHECK sy-subrc IS INITIAL.
313 *
314 *        lv_name = <fs_component>-name.
315 *
316 *        DATA(l_type) = cl_abap_typedescr=>describe_by_data( <fv_value> ).
317 *        CASE  l_type->kind.
318 *          WHEN cl_abap_typedescr=>kind_table .
319 *            ASSIGN <fv_value> TO <ft_data>.
320 *            LOOP AT <ft_data> ASSIGNING <fs_data>.
321 *              process( im_node = lo_element
322 *                       im_name = lv_name
323 *                       im_data = <fs_data> ).
324 *            ENDLOOP.
325 *          WHEN OTHERS.
326 *            process( im_node = lo_element
327 *                     im_name = lv_name
328 *                     im_data = <fv_value> ).
329 *        ENDCASE.
330 *      ENDLOOP.
331 *
332 *    WHEN OTHERS.
333 *      MESSAGE 'Import Structure!' TYPE 'E' RAISING type_error.
334 *  ENDCASE.
335 *
336 *  IF lo_element IS BOUND.
337 *    im_node->append_child( lo_element ).
338 *  ENDIF.
339 *
340 *ENDMETHOD.
341 ENDMETHOD.
342 
343 
344 * <SIGNATURE>---------------------------------------------------------------------------------------+
345 * | Instance Private Method ZCL_XML_UTIL->TRAVERSE
346 * +-------------------------------------------------------------------------------------------------+
347 * | [--->] IM_CURRENT_NODE                TYPE REF TO IF_IXML_NODE
348 * | [<-->] CH_DATA                        TYPE        ANY
349 * | [EXC!] TYPE_NOT_FOUND
350 * +--------------------------------------------------------------------------------------</SIGNATURE>
351 METHOD traverse.
352   DATA :
353     lo_type      TYPE REF TO cl_abap_typedescr,
354     lo_struct    TYPE REF TO cl_abap_structdescr,
355     lo_table     TYPE REF TO cl_abap_tabledescr,
356     lo_data      TYPE REF TO data,
357     lo_iterator  TYPE REF TO if_ixml_node_iterator,
358     lo_node_list TYPE REF TO if_ixml_node_list,
359     lo_node      TYPE REF TO if_ixml_node,
360     lv_node_name TYPE string VALUE IS INITIAL,
361     lv_match     TYPE boolean.
362 
363   FIELD-SYMBOLS :
364     <ft_data>      TYPE STANDARD TABLE,
365     <fs_component> TYPE abap_compdescr,
366     <fs_data>      TYPE any,
367     <fv_value>     TYPE any.
368 
369 * determine ABAP/4 data type, support only:
370 * - simple type
371 * - structure
372 * - table type
373   lo_type = cl_abap_typedescr=>describe_by_data( ch_data ).
374 
375   CASE lo_type->kind.
376     WHEN cl_abap_typedescr=>kind_elem.
377       ch_data = im_current_node->get_value( ).
378 
379     WHEN cl_abap_typedescr=>kind_struct.
380       lo_node_list = im_current_node->get_children( ).
381 
382 *     process each structure component independently
383       lo_struct ?= cl_abap_structdescr=>describe_by_data( ch_data ).
384       LOOP AT lo_struct->components ASSIGNING <fs_component>.
385         ASSIGN COMPONENT <fs_component>-name OF STRUCTURE ch_data TO <fv_value>.
386         CHECK sy-subrc IS INITIAL.
387 
388 *       create new iterator with each step
389         lo_iterator = lo_node_list->create_iterator( ).
390         lo_node = lo_iterator->get_next( ).
391 
392         WHILE lo_node  IS BOUND
393            OR lv_match EQ abap_true.
394 
395 *         xml element names can contain lower case characters
396           lv_node_name = to_upper( lo_node->get_name( ) ).
397 
398           IF lv_node_name EQ <fs_component>-name.
399             lv_match = abap_true.
400             EXIT.
401           ENDIF.
402 
403           lo_node = lo_iterator->get_next( ).
404         ENDWHILE.
405 
406         CHECK lv_match EQ abap_true.
407         traverse( EXPORTING im_current_node = lo_node
408                   CHANGING  ch_data         = <fv_value> ).
409         CLEAR : lv_match.
410       ENDLOOP.
411 
412     WHEN cl_abap_typedescr=>kind_table.
413       lo_table ?= cl_abap_tabledescr=>describe_by_data( ch_data ).
414       CREATE DATA lo_data TYPE HANDLE lo_table.
415       ASSIGN lo_data->* TO <ft_data>.
416 
417       DATA(lv_current_node_name) = im_current_node->get_name( ) .   "当前表节点
418       DATA(lo_parent_node) = im_current_node->get_parent( ).        "父节点
419       lo_node_list = lo_parent_node->get_children( ).
420       lo_iterator = lo_node_list->create_iterator( ).
421       lo_node = lo_iterator->get_next( ).
422 
423       CLEAR:lv_match.
424       WHILE lo_node  IS BOUND.                                     "父节点下层依次取节点
425         lv_node_name = lo_node->get_name( ) .
426 
427         IF lv_node_name EQ lv_current_node_name.   "如果当前节点等于父节点下层节点,则匹配
428           APPEND INITIAL LINE TO <ft_data> ASSIGNING <fs_data>.
429           traverse( EXPORTING im_current_node = lo_node
430                     CHANGING  ch_data         = <fs_data> ).
431         ENDIF.
432 
433         lo_node = lo_iterator->get_next( ).
434       ENDWHILE.
435 
436       IF NOT <ft_data> IS INITIAL.
437         ch_data = <ft_data>.
438       ENDIF.
439 
440     WHEN OTHERS.
441       TRY.
442           RAISE type_not_found.
443       ENDTRY.
444   ENDCASE.
445 
446 ENDMETHOD.
447 
448 
449 * <SIGNATURE>---------------------------------------------------------------------------------------+
450 * | Instance Public Method ZCL_XML_UTIL->XML_TO_ABAP
451 * +-------------------------------------------------------------------------------------------------+
452 * | [--->] IM_CONTENT                     TYPE        STRING(optional)
453 * | [--->] IM_CONTENT_X                   TYPE        XSTRING(optional)
454 * | [<---] EX_DATA                        TYPE        ANY
455 * +--------------------------------------------------------------------------------------</SIGNATURE>
456 METHOD xml_to_abap.
457 
458   CLEAR : ex_data.
459 
460   DATA :
461     lo_istream        TYPE REF TO if_ixml_istream,
462     lo_stream_factory TYPE REF TO if_ixml_stream_factory,
463     lo_iterator       TYPE REF TO if_ixml_node_iterator.
464 
465   IF im_content IS INITIAL AND im_content_x IS INITIAL.
466     RETURN.
467   ENDIF.
468 
469   IF NOT ex_data IS REQUESTED.
470     RETURN.
471   ENDIF.
472 
473 * create .xml document
474   mo_document = mo_ixml->create_document( ).
475 
476   lo_stream_factory = mo_ixml->create_stream_factory( ).
477 
478   IF im_content IS SUPPLIED.
479     lo_istream = lo_stream_factory->create_istream_string( im_content ).
480   ELSEIF im_content_x IS SUPPLIED.
481     lo_istream = lo_stream_factory->create_istream_xstring( im_content_x ).
482   ENDIF.
483 
484 
485 * parse .xml document with given input stream
486   IF mo_ixml->create_parser(
487       document       = mo_document
488       istream        = lo_istream
489       stream_factory = lo_stream_factory )->parse( ) IS INITIAL.
490 
491 *   create iterator   <NODE>#document
492     lo_iterator = mo_document->create_iterator( 0 ).
493 
494 *   skip #document element
495     lo_iterator->get_next( ).
496 
497 *   start with root  <NODE>docinfo
498     traverse( EXPORTING im_current_node = lo_iterator->get_next( )
499               CHANGING  ch_data         = ex_data ).
500   ENDIF.
501   FREE : mo_document.
502 
503 ENDMETHOD.
504 ENDCLASS.

 

 

测试结果:

 

不会出现双节点,arry1和test公用一个root节点也没问题。

 

 

 反编译,XML2ABAP也没问题

 

posted @ 2021-12-24 14:18  yangliu11223  阅读(210)  评论(0)    收藏  举报