SAP Abap复杂Xml处理 - 关于Xml转Abap内表

此方法参考ABAP老白原函数基础上进行改造,支持更多Xml格式文件处理。

原文来自https://mp.weixin.qq.com/s/NfnAFYI11xtHyRz6Q8eAaw

XML表示数组(内表)有两种格式,分别是

对于SAP来说默认生成第二种格式,但是如果外部系统只提供第一种格式的话,就需要我们进行处理了。日常SAP处理Xml非常麻烦,因为当时我开发需求中Xml格式非常复杂,所以老白的函数不支持处理此类Xml文件,我在此基础上对函数进行了调整,并进行了一些优化,可以支持比较复杂的Xml文件处理,包括多级深层结构,且支持不同父级标签包含相同标签名的子标签等,应该能支持95%的Xml情况,唯一的问题可能是当Xml特别大的时候,可能处理会非常慢,开发这个函数的时候需要处理的Xml文件有30M左右,需要替换的标签高达10W条,所以处理非常慢,可能不适合特别大的xml文件,支持正常的Xml文件来说还是非常好用。

ZXML_TRANSFER_ITEMTAG3

FUNCTION zxml_transfer_itemtag3.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     REFERENCE(XMLIN) TYPE  STRING
*"  EXPORTING
*"     REFERENCE(XMLSTR) TYPE  STRING
*"  TABLES
*"      TAGTAB STRUCTURE  ZXML_NODEN_MAPPING
*"----------------------------------------------------------------------
  DATA: maptab TYPE TABLE OF zxml_noden_mapping.
  DATA: maptab1 TYPE TABLE OF zxml_noden_mapping.
  FIELD-SYMBOLS:<fs_maptab> TYPE zxml_noden_mapping.
  DATA: tagc(100).
  DATA: moff TYPE i .
  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 xmlxstr  TYPE xstring.
  DATA istream  TYPE REF TO if_ixml_istream.
  DATA parser   TYPE REF TO if_ixml_parser.
  DATA:lv_index TYPE sy-tabix.
  DATA:lv_itext TYPE char50.
  DATA:lv_otext TYPE char50.
  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.
  maptab = VALUE #( FOR ls_tagtab IN tagtab
                         (
                         frstr = ls_tagtab-frstr
*                         fastr = ls_tagtab-fastr
*                         fastr1 = ls_tagtab-fastr1
                         tostr  =  'ITEM' && ls_tagtab-frstr
                         )
                         ).
  CALL FUNCTION 'ZXML_STRING_REBUILD1'
    EXPORTING
      xmlin         = xmlstr
      character_set = ''
    IMPORTING
      xmlout        = xmlstr
    TABLES
      maptab        = maptab
      maptab1       = maptab1
    EXCEPTIONS
      xml_error     = 1.
  IF sy-subrc <> 0.
    MESSAGE e000(oo) WITH '转换出错'.
  ENDIF.
  "动态替换
  SORT maptab1 BY frstr tostr."去重
  DELETE ADJACENT DUPLICATES FROM maptab1 COMPARING frstr tostr.
  REFRESH maptab.

  DESCRIBE TABLE maptab1 LINES gv_lines.
  GET TIME STAMP FIELD gv_start.
  CLEAR:gv_tabix.
  LOOP AT maptab1 ASSIGNING <fs_maptab>.
    ADD 1 TO gv_tabix.
    PERFORM frm_indicator USING gv_tabix.
    CLEAR moff.
    lv_itext = '<' && <fs_maptab>-tostr && '>'.
    lv_otext = '</' && <fs_maptab>-tostr && '>'.
    FIND FIRST OCCURRENCE OF REGEX lv_itext IN SECTION OFFSET moff OF xmlstr
                                      MATCH OFFSET moff.
    IF sy-subrc = 0.
      tagc = '<' && <fs_maptab>-frstr && '>'.
      CONCATENATE xmlstr(moff) tagc xmlstr+moff INTO xmlstr.
    ENDIF.

    FIND ALL OCCURRENCES OF REGEX lv_otext IN SECTION OFFSET moff OF xmlstr
                                      MATCH OFFSET moff.
    IF sy-subrc = 0.
      lv_index = cl_abap_list_utilities=>dynamic_output_length( lv_otext ).
      moff = moff + lv_index.
      tagc = '</' && <fs_maptab>-frstr && '>'.
      CONCATENATE xmlstr(moff) tagc xmlstr+moff INTO xmlstr.
    ENDIF.
  ENDLOOP.
  REPLACE ALL OCCURRENCES OF REGEX '<ITEM\w+>' IN xmlstr WITH '<item>'.
  REPLACE ALL OCCURRENCES OF REGEX '</ITEM\w+>' IN xmlstr WITH '</item>'.
  "检查转换是否正确
  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.
    MESSAGE e000(oo) WITH '转换出错'.
  ENDIF.
ENDFUNCTION.

ZXML_STRING_REBUILD1

FUNCTION zxml_string_rebuild1.
*"----------------------------------------------------------------------
*"*"本地接口:
*"  IMPORTING
*"     REFERENCE(XMLIN) TYPE  STRING
*"     REFERENCE(CASE) TYPE  C OPTIONAL
*"     REFERENCE(PRETTY) TYPE  C OPTIONAL
*"     REFERENCE(CHARACTER_SET) TYPE  STRING DEFAULT 'UTF-8'
*"  EXPORTING
*"     REFERENCE(XMLOUT) TYPE  STRING
*"     REFERENCE(XMLOUTX) TYPE  XSTRING
*"     REFERENCE(CDATA) TYPE  RSTT_T_STRINGS
*"  TABLES
*"      MAPTAB STRUCTURE  ZXML_NODEN_MAPPING
*"      MAPTAB1 STRUCTURE  ZXML_NODEN_MAPPING
*"  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:lv_node TYPE REF TO if_ixml_node."父节点
  DATA xmlxstr  TYPE xstring.
  DATA str      TYPE string.
  DATA wa_cdata TYPE rstt_s_string.
  DATA:lv_name TYPE string.
  DATA:lv_name1 TYPE string.
  DATA:lv_index TYPE i.
  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.
      lv_name = node->get_name( )."替换为大写再比较字段名
      TRANSLATE lv_name TO UPPER CASE .
      READ TABLE maptab WITH KEY frstr = lv_name.
      IF sy-subrc = 0.
        lv_node = node->get_parent( )."获取父节点
        lv_name1 = lv_node->get_name( ).
        IF lv_node IS INITIAL.
          str = maptab-tostr.
          node->set_name( str ).
          MOVE-CORRESPONDING maptab TO maptab1.
          APPEND maptab1 TO maptab1.
          EXIT.
        ENDIF.
        lv_index = lv_node->get_gid( )."返回父级列表Gid(唯一)
        str = maptab-tostr && lv_index.
        node->set_name( str ).
        MOVE-CORRESPONDING maptab TO maptab1.
        maptab1-tostr = str.
        APPEND maptab1 TO maptab1.
        CLEAR maptab1.
      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.
*  BREAK-POINT.
  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.

ZXML_STRING_TO_DATA

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
*"----------------------------------------------------------------------
  DATA: go_xml TYPE REF TO cl_xml_document .
  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.
ENDFUNCTION.

下面是简单的测试程序,

*&---------------------------------------------------------------------*
*& Report Z_TEST_DNE1
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zdemo_04.
*Address
DATA: BEGIN OF wa_address ,
        streetname              TYPE char100,
        number                  TYPE char100,
        additionaladdressdetail TYPE char100,
        building                TYPE char100,
        city                    TYPE char100,
        postalcode              TYPE char100,
        region                  TYPE char100,
        country                 TYPE char100,
        addresstype             TYPE char100,
      END OF wa_address.
*companystructure
DATA: BEGIN OF wa_companystructure ,
        registrationnumber TYPE char100,
        name               TYPE char100,
        address            LIKE TABLE OF wa_address,
      END OF wa_companystructure.

*masterfiles-Customers-Customer
DATA: BEGIN OF wa_customer ,
        companystructure     LIKE TABLE OF wa_companystructure, "下一级
        customerid           TYPE char100,
        selfbillingindicator TYPE char100,
        accountid            TYPE char100,
        openingdebitbalance  TYPE char100,
        openingcreditbalance TYPE char100,
        closingdebitbalance  TYPE char100,
        closingcreditbalance TYPE char100,
      END OF wa_customer.

DATA: BEGIN OF wa_supplier ,
        companystructure     LIKE TABLE OF wa_companystructure, "下一级
        supplierid           TYPE char100,
        selfbillingindicator TYPE char100,
        accountid            TYPE char100,
        openingdebitbalance  TYPE char100,
        openingcreditbalance TYPE char100,
        closingdebitbalance  TYPE char100,
        closingcreditbalance TYPE char100,
      END OF wa_supplier.
*masterfiles-Customers
DATA: BEGIN OF wa_customers ,
        customer LIKE TABLE OF wa_customer, "下一级
      END OF wa_customers.
*masterfiles-Suppliers
DATA: BEGIN OF wa_suppliers ,
        supplier LIKE TABLE OF wa_supplier, "下一级
      END OF wa_suppliers.


DATA: BEGIN OF wa_err  ,
        err1 TYPE string,
        err2 TYPE string,
      END OF wa_err.
DATA: BEGIN OF wa_appaysavz  ,
        errcod TYPE string,
        errmsg TYPE string,
        paytim TYPE string,
        recnum TYPE string,
        refnbr TYPE string,
        remark TYPE string,
        err    LIKE TABLE OF wa_err,
      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,
        err    LIKE TABLE OF wa_err,
      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_masterfiles ,
        info      LIKE TABLE OF wa_info,
        appaysavy LIKE TABLE OF wa_appaysavy,
        appaysavz LIKE TABLE OF wa_appaysavz,
        sycomretz LIKE wa_sycomretz,
        customers LIKE TABLE OF wa_customers, "下一级
        suppliers LIKE TABLE OF wa_suppliers, "下一级
      END OF wa_masterfiles.

DATA: BEGIN OF wa_auditfile ,
        masterfiles LIKE TABLE OF wa_masterfiles, "下一级
      END OF wa_auditfile.


DATA:gt_mapping TYPE TABLE OF zxml_noden_mapping,
     gs_mapping TYPE zxml_noden_mapping.
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"?>'
 '<AuditFile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="mfp:anaf:dgti:d406:declaratie:v1" xsi:schemaLocation="urn:StandardAuditFile-Taxation-Financial:RO Romanian_SAF-T_Financial_Schema_v_2.1.xsd">'
              '<MASTERFILES>'
              '  <INFO>'
              '    <ERPTYP>H</ERPTYP>'
              '    <ERRMSG/>'
              '    <FUNNAM>ERPAYSAV</FUNNAM>'
              '    <RETCOD>0000000</RETCOD>'
               '    <ERR>'
              '    <ERR1>0000001</ERR1>'
              '    <ERR2>0000002</ERR2>'
              '    </ERR>'
              '    <ERR>'
              '    <ERR1>0000003</ERR1>'
              '    <ERR2>0000004</ERR2>'
              '    </ERR>'
              '  </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:FK21092321148</REFNBR>'
              '    <REMARK/>'
              '    <ERR>'
              '    <ERR1>0000001</ERR1>'
              '    <ERR2>0000002</ERR2>'
              '    </ERR>'
              '    <ERR>'
              '    <ERR1>0000003</ERR1>'
              '    <ERR2>0000004</ERR2>'
              '    </ERR>'
              '  </APPAYSAVZ>'
              '  <SYCOMRETZ>'
              '    <ERRCOD>0000000</ERRCOD>'
              '    <ERRDTL/>'
              '  </SYCOMRETZ>'
                            ' <CUSTOMERS>'
              ' <CUSTOMER>'
              '<COMPANYSTRUCTURE>'
              '<REGISTRATIONNUMBER>0010102512</REGISTRATIONNUMBER>'
              '<NAME>ELTON CORPORATION SA</NAME>'
              '<ADDRESS>'
              '<STREETNAME>CAMPULUI</STREETNAME>'
              '<NUMBER>5</NUMBER>'
              '<CITY>PANTELIMON                 </CITY>'
              '<POSTALCODE>NULL</POSTALCODE>'
              '<COUNTRY>RO</COUNTRY>'
              '<ADDRESSTYPE>STREETADDRESS</ADDRESSTYPE>'
              '</ADDRESS>'
              '</COMPANYSTRUCTURE>'
              '<CUSTOMERID>0010102512</CUSTOMERID>'
              '<SELFBILLINGINDICATOR>0</SELFBILLINGINDICATOR>'
              '<ACCOUNTID>4111</ACCOUNTID>'
              '<OPENINGCREDITBALANCE>0.00</OPENINGCREDITBALANCE>'
              '<CLOSINGCREDITBALANCE>0.00</CLOSINGCREDITBALANCE>'
              '</CUSTOMER>'
                            ' <CUSTOMER>'
              '<COMPANYSTRUCTURE>'
              '<REGISTRATIONNUMBER>0010102512</REGISTRATIONNUMBER>'
              '<NAME>ELTON CORPORATION SA</NAME>'
              '<ADDRESS>'
              '<STREETNAME>CAMPULUI</STREETNAME>'
              '<NUMBER>5</NUMBER>'
              '<CITY>PANTELIMON                 </CITY>'
              '<POSTALCODE>NULL</POSTALCODE>'
              '<COUNTRY>RO</COUNTRY>'
              '<ADDRESSTYPE>STREETADDRESS</ADDRESSTYPE>'
              '</ADDRESS>'
              '</COMPANYSTRUCTURE>'
              '<CUSTOMERID>0010102512</CUSTOMERID>'
              '<SELFBILLINGINDICATOR>0</SELFBILLINGINDICATOR>'
              '<ACCOUNTID>4111</ACCOUNTID>'
              '<OPENINGCREDITBALANCE>0.00</OPENINGCREDITBALANCE>'
              '<CLOSINGCREDITBALANCE>0.00</CLOSINGCREDITBALANCE>'
              '</CUSTOMER>'
              ' </CUSTOMERS>'
             '<SUPPLIERS>'
             '<SUPPLIER>'
             '<COMPANYSTRUCTURE>'
             '<REGISTRATIONNUMBER>0010556705</REGISTRATIONNUMBER>'
             '<NAME>ROMTECHNOLOGY TRANS-VAMAL  SRL</NAME>'
             '<ADDRESS>'
             '<STREETNAME>STR.ALEXANDRU CEL BUN NR.25</STREETNAME>'
             '<CITY>CONSTANTA</CITY>'
             '<POSTALCODE>NULL</POSTALCODE>'
             '<COUNTRY>RO</COUNTRY>'
             '<ADDRESSTYPE>STREETADDRESS</ADDRESSTYPE>'
             '</ADDRESS>'
             '</COMPANYSTRUCTURE>'
             '<SUPPLIERID>0010556705</SUPPLIERID>'
             '<SELFBILLINGINDICATOR>0</SELFBILLINGINDICATOR>'
             '<ACCOUNTID>401</ACCOUNTID>'
             '<OPENINGCREDITBALANCE>0.00</OPENINGCREDITBALANCE>'
             '<CLOSINGCREDITBALANCE>0.00</CLOSINGCREDITBALANCE>'
             '</SUPPLIER>'
                          '<SUPPLIER>'
             '<COMPANYSTRUCTURE>'
             '<REGISTRATIONNUMBER>0010556705</REGISTRATIONNUMBER>'
             '<NAME>ROMTECHNOLOGY TRANS-VAMAL  SRL</NAME>'
             '<ADDRESS>'
             '<STREETNAME>STR.ALEXANDRU CEL BUN NR.25</STREETNAME>'
             '<CITY>CONSTANTA</CITY>'
             '<POSTALCODE>NULL</POSTALCODE>'
             '<COUNTRY>RO</COUNTRY>'
             '<ADDRESSTYPE>STREETADDRESS</ADDRESSTYPE>'
             '</ADDRESS>'
             '</COMPANYSTRUCTURE>'
             '<SUPPLIERID>0010556705</SUPPLIERID>'
             '<SELFBILLINGINDICATOR>0</SELFBILLINGINDICATOR>'
             '<ACCOUNTID>401</ACCOUNTID>'
             '<OPENINGCREDITBALANCE>0.00</OPENINGCREDITBALANCE>'
             '<CLOSINGCREDITBALANCE>0.00</CLOSINGCREDITBALANCE>'
             '</SUPPLIER>'
             '</SUPPLIERS>'
              '</MASTERFILES>'
              '</AuditFile>'
      INTO xmlstr.
  DEFINE insert_tag.
    gs_mapping-frstr = &1.
*    gs_mapping-fastr = &2."上级节点
*    gs_mapping-fastr1 = &3."再上一级节点
    APPEND gs_mapping to gt_mapping.
    CLEAR gs_mapping.
  END-OF-DEFINITION.


  "所有表结构
  CLEAR:gt_mapping.
  insert_tag :
                  'MASTERFILES',
                  'INFO',
                  'ERR',
                  'APPAYSAVY' ,
                  'APPAYSAVZ' ,
                  'CUSTOMERS',
                  'CUSTOMER',
                  'SUPPLIERS' ,
                  'SUPPLIER' ,
                  'COMPANYSTRUCTURE',
                  'ADDRESS'.

  CALL FUNCTION 'ZXML_TRANSFER_ITEMTAG3'
    EXPORTING
      xmlin  = xmlstr
    IMPORTING
      xmlstr = xmlstr
    TABLES
      tagtab = gt_mapping.

  "反序列化
  CALL FUNCTION 'ZXML_STRING_TO_DATA'
    EXPORTING
      xmlstr = xmlstr
    IMPORTING
      data   = wa_auditfile.

  BREAK-POINT.

使用ZXML_STRING_TO_DATA反序列化XML的时候,SAP对象的元素定义和XML的格式并不需要一一对应。比如银行接口,针对不同的业务会返回不同格式的XML,这个时候只要定义一个包含这些格式元素全集的深层结构就OK了

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值