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也没问题
本文来自博客园,作者:yangliu11223,转载请注明原文链接:https://www.cnblogs.com/yangliu11223/p/15727175.html