ABAP和外部系统做接口的时候,XML和JSON是两种常用的数据传输格式,它们各自有一些优缺点,如下所述:
XML:
优点:XML具有较好的可扩展性和灵活性,可以通过定义DTD或XSD等文档类型定义来定义和验证数据结构。XML的标记语言具有很强的可读性,易于人们理解和处理,对于需要手动编辑的文件而言,这是一个重要的优势。
缺点:XML语法比JSON复杂,需要更多的字符和标签来表示相同的信息,这导致XML的文件大小较大。在处理大型数据时,会带来较高的处理负载和内存占用。与JSON相比,XML处理速度较慢。
JSON:
优点:JSON比XML更轻量级,因此在传输和处理大量数据时更有效率。语法简单,易于阅读和编写,并且可以通过各种编程语言和平台进行处理。
缺点:JSON缺乏XML的严格数据类型,无法通过DTD或XSD等文档类型定义来验证数据结构的正确性。不支持注释,这使得JSON文件不像XML那样容易被人类读取和编辑,对于需要手动编辑的文件而言,JSON的可读性不如XML。
实事求是的讲,就ABAP做的接口而言,大多都是固定的数据格式,不需要人工解读,DTD和XSD在接口使用场景下更是毫无用处,所以XML的优点在这儿无任何卵用,反而是文件大、效率低、处理起来恶心,相比JSON一无是处。
所以建议使用JSON来代替XML。
正是因为XML处理起来太麻烦,所以给大家提供几个有用的函数,有了这几个函数足矣应付90+%的XML格式接口场景了。
FUNCTION zxml_data_to_string . *"---------------------------------------------------------------------- *"*"局部接口: *" IMPORTING *" REFERENCE(DATA) TYPE ANY *" REFERENCE(CASE) TYPE C OPTIONAL *" REFERENCE(PRETTY) TYPE C OPTIONAL *" REFERENCE(ROOTNAME) TYPE STRING DEFAULT 'BOOT' *" REFERENCE(CHARACTER_SET) TYPE STRING DEFAULT 'UTF-8' *" REFERENCE(DCXMLINIT) TYPE DCXMLINIT DEFAULT 'N' *" EXPORTING *" REFERENCE(XMLSTR) TYPE STRING *" REFERENCE(XMLXSTR) TYPE XSTRING *" TABLES *" MAPTAB STRUCTURE ZXML_NODEN_MAPPING OPTIONAL *" EXCEPTIONS *" DATA_TO_DOM_ERROR *"---------------------------------------------------------------------- DATA ifxml TYPE REF TO if_ixml. DATA factory TYPE REF TO if_ixml_stream_factory. DATA document TYPE REF TO if_ixml_document. DATA node TYPE REF TO if_ixml_node. DATA iterator TYPE REF TO if_ixml_node_iterator. DATA ostream TYPE REF TO if_ixml_ostream. DATA encoding TYPE REF TO if_ixml_encoding . DATA element TYPE REF TO if_ixml_element. DATA retval TYPE i. DATA str TYPE string. DATA control TYPE dcxmlsercl. ifxml = cl_ixml=>create( ). document = ifxml->create_document( ). factory = ifxml->create_stream_factory( ). encoding = ifxml->create_encoding( byte_order = 0 character_set = character_set ). control-init_treat = dcxmlinit . CALL FUNCTION 'SDIXML_DATA_TO_DOM' EXPORTING name = rootname dataobject = data control = control IMPORTING data_as_dom = element CHANGING document = document EXCEPTIONS illegal_name = 1 OTHERS = 2. IF element IS INITIAL. RAISE data_to_dom_error. ELSE. retval = document->append_child( new_child = element ). ENDIF. IF case <> '' OR maptab[] IS NOT INITIAL. iterator = document->create_iterator( ). DO. node = iterator->get_next( ). IF node IS INITIAL. EXIT. ENDIF. IF node->get_type( ) = if_ixml_node=>co_node_element. READ TABLE maptab WITH KEY frstr = node->get_name( ). IF sy-subrc = 0. str = maptab-tostr. node->set_name( str ). ELSE. CASE case. WHEN 'U'. node->set_name( to_upper( node->get_name( ) ) ). WHEN 'L'. node->set_name( to_lower( node->get_name( ) ) ). WHEN OTHERS. ENDCASE. ENDIF. ENDIF. ENDDO. ENDIF. ostream = factory->create_ostream_xstring( string = xmlxstr ). ostream->set_encoding( encoding = encoding ). ostream->set_pretty_print( pretty_print = pretty ). document->render( ostream = ostream ). xmlstr = cl_abap_codepage=>convert_from( source = xmlxstr codepage = character_set ). ENDFUNCTION.
讯享网
2、XML转为SAP数据
讯享网FUNCTION zxml_string_to_data . *"---------------------------------------------------------------------- *"*"局部接口: *" IMPORTING *" REFERENCE(XMLSTR) TYPE STRING *" REFERENCE(ICDATA) TYPE CHAR1 OPTIONAL *" EXPORTING *" REFERENCE(DATA) TYPE ANY *" REFERENCE(SUBRC) TYPE SY-SUBRC *"---------------------------------------------------------------------- *如果要取CDATA数据 *程序:LSDIXMLF04,FORM get_cdata,做如下修改: * ... * DATA: icdata. * * CLEAR value. * IMPORT icdata FROM MEMORY ID 'ZXML_STRING_TO_DATA_ICDATA'. * IF icdata IS NOT INITIAL . * filter = element->create_filter_node_type( 48 ). * ELSE. * filter = element->create_filter_node_type( * if_ixml_node=>co_node_text ). * ENDIF. * iterator = element->create_iterator( 1 ). * ... DATA: go_xml TYPE REF TO cl_xml_document . IF icdata IS NOT INITIAL. EXPORT icdata TO MEMORY ID 'ZXML_STRING_TO_DATA_ICDATA'. "LSDIXMLF04 ENDIF. IF go_xml IS INITIAL. CREATE OBJECT go_xml. ENDIF. CALL METHOD go_xml->parse_string EXPORTING stream = xmlstr RECEIVING retcode = subrc. CALL METHOD go_xml->get_data IMPORTING retcode = subrc CHANGING dataobject = data. FREE MEMORY ID 'ZXML_STRING_TO_DATA_ICDATA'. ENDFUNCTION.
3、对XML重新处理,比如标签名的批量更改、字符集的转换等
FUNCTION zxml_string_rebuild . *"---------------------------------------------------------------------- *"*"局部接口: *" IMPORTING *" REFERENCE(XMLIN) TYPE STRING *" REFERENCE(CASE) TYPE C OPTIONAL *" REFERENCE(PRETTY) TYPE C OPTIONAL *" REFERENCE(CHARACTER_SET) TYPE STRING DEFAULT 'UTF-8' *" EXPORTING *" VALUE(XMLOUT) TYPE STRING *" VALUE(XMLOUTX) TYPE XSTRING *" VALUE(CDATA) TYPE RSTT_T_STRINGS *" TABLES *" MAPTAB STRUCTURE ZXML_NODEN_MAPPING OPTIONAL *" EXCEPTIONS *" XML_ERROR *"---------------------------------------------------------------------- DATA ifxml TYPE REF TO if_ixml. DATA factory TYPE REF TO if_ixml_stream_factory. DATA document TYPE REF TO if_ixml_document. DATA iterator TYPE REF TO if_ixml_node_iterator. DATA node TYPE REF TO if_ixml_node. DATA parser TYPE REF TO if_ixml_parser. DATA istream TYPE REF TO if_ixml_istream. DATA ostream TYPE REF TO if_ixml_ostream. DATA encoding TYPE REF TO if_ixml_encoding . * DATA retval TYPE i. DATA xmlxstr TYPE xstring. DATA str TYPE string. DATA wa_cdata TYPE rstt_s_string. ifxml = cl_ixml=>create( ). document = ifxml->create_document( ). factory = ifxml->create_stream_factory( ). xmlxstr = cl_abap_codepage=>convert_to( source = xmlin ). istream = factory->create_istream_xstring( string = xmlxstr ). parser = ifxml->create_parser( document = document stream_factory = factory istream = istream ). IF parser->parse( ) <> 0. RAISE xml_error. ENDIF. iterator = document->create_iterator( ). DO. node = iterator->get_next( ). IF node IS INITIAL. EXIT. ENDIF. IF node->get_type( ) = if_ixml_node=>co_node_element. READ TABLE maptab WITH KEY frstr = node->get_name( ). IF sy-subrc = 0. str = maptab-tostr. node->set_name( str ). ELSE. CASE case. WHEN 'U'. node->set_name( to_upper( node->get_name( ) ) ). WHEN 'L'. node->set_name( to_lower( node->get_name( ) ) ). ENDCASE. ENDIF. ELSEIF node->get_type( ) = if_ixml_node=>co_node_cdata_section. wa_cdata-string = node->get_value( ). APPEND wa_cdata TO cdata. ENDIF. ENDDO. ostream = factory->create_ostream_xstring( string = xmloutx ). IF character_set IS NOT INITIAL. encoding = ifxml->create_encoding( byte_order = 0 character_set = character_set ). ostream->set_encoding( encoding = encoding ). ENDIF. IF pretty IS NOT INITIAL. ostream->set_pretty_print( pretty_print = pretty ). ENDIF. document->render( ostream = ostream ). xmlout = cl_abap_codepage=>convert_from( xmloutx ). ENDFUNCTION.
4、XML表示数组(内表)有两种格式,分别是

和:

讯享网FUNCTION ZXML_TRANSFER_ITEMTAG1 . *"---------------------------------------------------------------------- *"*"局部接口: *" IMPORTING *" VALUE(XMLIN) TYPE STRING *" EXPORTING *" VALUE(XMLSTR) TYPE STRING *" TABLES *" TAGTAB *"---------------------------------------------------------------------- DATA: maptab TYPE TABLE OF zxml_noden_mapping WITH HEADER LINE. DATA: tagc(100). DATA: moff TYPE i . CHECK xmlin IS NOT INITIAL. FIND FIRST OCCURRENCE OF '<item>' IN xmlin . IF sy-subrc = 0. MESSAGE e000(oo) WITH '原始XML已经包含<item>标签,无法转换'. ENDIF. xmlstr = xmlin. LOOP AT tagtab. CLEAR: maptab,maptab[]. maptab-frstr = tagtab. maptab-tostr = 'item'. APPEND maptab. CALL FUNCTION 'ZXML_STRING_REBUILD' EXPORTING xmlin = xmlstr character_set = '' IMPORTING xmlout = xmlstr TABLES maptab = maptab EXCEPTIONS xml_error = 1. IF sy-subrc <> 0. MESSAGE e000(oo) WITH '转换出错'. ELSE. FIND FIRST OCCURRENCE OF '<item>' IN SECTION OFFSET moff OF xmlstr MATCH OFFSET moff. IF sy-subrc = 0. tagc = '<' && tagtab && '>'. CONCATENATE xmlstr(moff) tagc xmlstr+moff INTO xmlstr. ENDIF. FIND ALL OCCURRENCES OF '</item>' IN SECTION OFFSET moff OF xmlstr MATCH OFFSET moff. IF sy-subrc = 0. moff = moff + 7. tagc = '</' && tagtab && '>'. CONCATENATE xmlstr(moff) tagc xmlstr+moff INTO xmlstr. ENDIF. ENDIF. ENDLOOP. ENDFUNCTION.
FUNCTION zxml_transfer_itemtag2 . *"---------------------------------------------------------------------- *"*"局部接口: *" IMPORTING *" VALUE(XMLIN) TYPE STRING *" EXPORTING *" VALUE(XMLSTR) TYPE STRING *" TABLES *" TAGTAB *"---------------------------------------------------------------------- DATA: regex(100). DATA: tagb(100), tage(100), tags(100). DATA: moff TYPE i , mlen TYPE i . CHECK xmlin IS NOT INITIAL. FIND FIRST OCCURRENCE OF '<item>' IN xmlin . IF sy-subrc <> 0. MESSAGE e000(oo) WITH '原始XML不包含<item>标签,无法转换'. ENDIF. xmlstr = xmlin. LOOP AT tagtab. tagb = '<' && tagtab && '>'. tage = '</' && tagtab && '>'. regex = tagb && '.*' && tage. FIND FIRST OCCURRENCE OF REGEX regex IN xmlstr MATCH OFFSET moff MATCH LENGTH mlen . IF sy-subrc = 0. REPLACE ALL OCCURRENCES OF '<item>' IN SECTION OFFSET moff LENGTH mlen OF xmlstr WITH tagb. ENDIF. FIND FIRST OCCURRENCE OF REGEX regex IN xmlstr MATCH OFFSET moff MATCH LENGTH mlen . IF sy-subrc = 0. REPLACE ALL OCCURRENCES OF '</item>' IN SECTION OFFSET moff LENGTH mlen OF xmlstr WITH tage. ENDIF. tags = tagb && tagb. REPLACE ALL OCCURRENCES OF tags IN xmlstr WITH tagb. tags = tage && tage. REPLACE ALL OCCURRENCES OF tags IN xmlstr WITH tage. ENDLOOP. ENDFUNCTION.
测试样例:
讯享网REPORT z_barry_testxml NO STANDARD PAGE HEADING. DATA: BEGIN OF wa_appaysavz , errcod TYPE string, errmsg TYPE string, paytim TYPE string, recnum TYPE string, refnbr TYPE string, remark TYPE string, END OF wa_appaysavz. DATA: BEGIN OF wa_appaysavy , busnbr TYPE string, exttx1 TYPE string, sqrnbr TYPE string, END OF wa_appaysavy. DATA: BEGIN OF wa_info , erptyp TYPE string, errmsg TYPE string, funnam TYPE string, retcod TYPE string, END OF wa_info. DATA: BEGIN OF wa_sycomretz, errcod TYPE string, errdtl TYPE string, errmsg TYPE string, END OF wa_sycomretz. DATA: BEGIN OF wa_cbserppgk , info LIKE wa_info, appaysavy LIKE TABLE OF wa_appaysavy, appaysavz LIKE TABLE OF wa_appaysavz, sycomretz LIKE wa_sycomretz, END OF wa_cbserppgk. DATA moff TYPE i . DATA xmlstr TYPE string. DATA maptab TYPE TABLE OF zxml_noden_mapping WITH HEADER LINE. DATA tagtab TYPE TABLE OF char100. START-OF-SELECTION. CONCATENATE '<?xml version="1.0" encoding="UTF-8"?>' '<CBSERPPGK>' ' <INFO>' ' <ERPTYP>H</ERPTYP>' ' <ERRMSG/>' ' <FUNNAM>ERPAYSAV</FUNNAM>' ' <RETCOD>0000000</RETCOD>' ' </INFO>' ' <APPAYSAVY>' ' <BUSNBR>0000001</BUSNBR>' ' <EXTTX1>0000001</EXTTX1>' ' <SQRNBR>0000001</SQRNBR>' ' </APPAYSAVY>' ' <APPAYSAVY>' ' <BUSNBR>0000002</BUSNBR>' ' <EXTTX1>0000002</EXTTX1>' ' <SQRNBR>0000002</SQRNBR>' ' </APPAYSAVY>' ' <APPAYSAVY>' ' <BUSNBR>0000003</BUSNBR>' ' <EXTTX1>0000003</EXTTX1>' ' <SQRNBR>0000003</SQRNBR>' ' </APPAYSAVY>' ' <APPAYSAVZ>' ' <ERRCOD>0000001</ERRCOD>' ' <ERRMSG>业务参考号重复!</ERRMSG>' ' <PAYTIM/>' ' <RECNUM>1</RECNUM>' ' <REFNBR>gp:FK</REFNBR>' ' <REMARK/>' ' </APPAYSAVZ>' ' <APPAYSAVZ>' ' <ERRCOD>0000001</ERRCOD>' ' <ERRMSG>业务参考号重复!</ERRMSG>' ' <PAYTIM/>' ' <RECNUM>1</RECNUM>' ' <REFNBR>gp:FK</REFNBR>' ' <REMARK/>' ' </APPAYSAVZ>' ' <SYCOMRETZ>' ' <ERRCOD>0000000</ERRCOD>' ' <ERRDTL/>' ' <ERRMSG/>' ' </SYCOMRETZ>' '</CBSERPPGK>' INTO xmlstr. "转换内表的标签格式 APPEND 'APPAYSAVY' TO tagtab. APPEND 'APPAYSAVZ' TO tagtab. CALL FUNCTION 'ZXML_TRANSFER_ITEMTAG1' EXPORTING xmlin = xmlstr IMPORTING xmlstr = xmlstr TABLES tagtab = tagtab. "反序列化 CALL FUNCTION 'ZXML_STRING_TO_DATA' EXPORTING xmlstr = xmlstr IMPORTING data = wa_cbserppgk. BREAK-POINT.
1、使用ZXML_STRING_TO_DATA反序列化XML的时候,SAP对象的元素定义和XML的格式并不需要一一对应。比如银行接口,针对不同的业务会返回不同格式的XML,这个时候只要定义一个包含这些格式元素全集的深层结构就OK了。
2、有时候需要直接发送二进制的XML给外部系统或者是下载到本地,ZXML_DATA_TO_STRING和ZXML_STRING_REBUILD都提供XSTRING格式的XML,在需要的时候,可以直接使用而不必再转换一次。
3、ZXML_TRANSFER_ITEMTAG1和2本来应该写成一个单独的函数,但这玩意用得少,没动力,不改了。
4、有时候外部系统会把数据写到CDATA里面,ZXML_STRING_TO_DATA函数是不能直接取到的,需要改一下源码才可,改源码的位置和代码写到ZXML_STRING_TO_DATA的注释里面了。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/75756.html