XML Schema Import Into an ABAP system
It sometimes happens… You do not have an SAP PI instance (or something similar), however you need to download (or upload) an XML file, and it is very hard to control the file structure. All you have is an XML schema provided by an external system, and there is a challenge – to re-create in SAP something similar to the file format described in the XSD. And remember – no SAP PI or other Integration Bus capable of doing the import on your behalf!
This tiny utility uses standard SAP ABAP Proxy mechanism to import the data definition and create respective DDIC objects. The process flow is very similar to Service Consumer creation in SPROXY transaction, however with this utility you can use directly use an XSD file (dummy WSDL is created automatically). The utility was also inspired by this blog – http://sapblog.rmtiwari.com.
Please note that in order to make this post easier to read, I’ve omitted some basic routines (e.g. for file selection dialogue, message output etc.).
Global data and selection-screen:
*&---------------------------------------------------------------------*
*& Report Z_IMPORT_XML_SCHEMA
*&
*&---------------------------------------------------------------------*
*& This reports imports an XSD file and calls standard ABAP/4 proxy generation
*& methods to (re-)create DDIC objects
*&---------------------------------------------------------------------*
REPORT z_import_xml_schema.
TYPE-POOLS: sprx,
trwbo.
CONSTANTS:
gc_lcl TYPE packname VALUE '$TMP'.
DATA:
go_proxy TYPE REF TO cl_proxy,
gv_xcontent TYPE xstring,
gv_wsdl TYPE xstring.
PARAMETERS:
p_xsdfn TYPE anyuri OBLIGATORY VALUE CHECK. "XML Schema file name
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME.
PARAMETERS:
p_pckg TYPE packname VALUE CHECK DEFAULT gc_lcl, " Package
p_trrq TYPE trkorr VALUE CHECK, " Transport request
p_prfx TYPE prx_prefix OBLIGATORY DEFAULT 'Z', " Prefix
p_actv AS CHECKBOX default 'X'. " Activate immediately
SELECTION-SCREEN END OF BLOCK b1.
" Transport request selection dialogue:
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_trrq.
PERFORM get_transport_request CHANGING p_trrq. "
" File name selection dialogue:
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_xsdfn.
PERFORM get_file_name CHANGING p_xsdfn. "
I have used the following sequence:
- File upload;
- Conversion to WSDL – format which is “native” for an ABAP/4 proxy generator;
- Instantiation of the proxy object – using a generated WSDL;
- DDIC update (and activation if desired);
Step 1 – File upload:
FORM upload_file USING iv_filename TYPE anyuri
CHANGING cv_xcontent TYPE xstring.
DATA: lo_slib_retriever TYPE REF TO if_slib_retriever,
lo_exception TYPE REF TO cx_root,
lv_fault TYPE xstring.
TRY.
lo_slib_retriever = cl_slib_entity_container=>create_retriever( ).
cv_xcontent = lo_slib_retriever->get_content( iv_filename ).
CATCH cx_slib INTO lo_exception.
PERFORM output_message USING 'E'
'Unable to read the file specified.'(urf).
STOP.
ENDTRY.
ENDFORM. "upload_file
Step 2 – WSDL conversion:
FORM xsd2wsdl USING iv_xcontent TYPE xstring
CHANGING cv_wsdl TYPE xstring.
DATA:
lv_message TYPE string,
lx_gen_error TYPE REF TO cx_proxy_gen_error.
TRY.
CALL METHOD cl_proxy_test_utils=>xsd2wsdl
EXPORTING
schema = iv_xcontent
RECEIVING
wsdl = cv_wsdl.
CATCH cx_proxy_gen_error INTO lx_gen_error .
lv_message = lx_gen_error->if_message~get_text( ).
PERFORM output_message USING 'E'
lv_message.
STOP.
ENDTRY.
ENDFORM. "xsd2wsdl
Step 3 – Instantiation of a proxy object:
FORM init_proxy USING iv_wsdl TYPE xstring
iv_pckg
iv_praefix
CHANGING co_proxy TYPE REF TO cl_proxy.
DATA:
lx_root TYPE REF TO cx_root,
lv_message TYPE string.
TRY.
CALL METHOD cl_proxy_test_utils=>wsdl2proxy
EXPORTING
wsdl = iv_wsdl
package = iv_pckg
praefix = iv_praefix
RECEIVING
proxy = co_proxy.
CATCH cx_proxy_gen_error INTO lx_root.
" LX_ROOT is checked below
CATCH cx_slib INTO lx_root.
" LX_ROOT is checked below
CATCH cx_sidl INTO lx_root.
" LX_ROOT is checked below
ENDTRY.
IF lx_root IS BOUND.
lv_message = lx_root->if_message~get_text( ).
PERFORM output_message USING 'E'
lv_message.
STOP.
ENDIF.
ENDFORM. "init_proxy
Step 4 – DDIC update….
FORM save_proxy USING io_proxy TYPE REF TO cl_proxy.
DATA:
lx_error TYPE REF TO cx_proxy_gen_error,
lv_message TYPE string.
TRY.
CALL METHOD io_proxy->save
CHANGING
transport_number = p_trrq.
CATCH cx_proxy_gen_error INTO lx_error .
lv_message = lx_error->if_message~get_text( ).
PERFORM output_message USING 'E'
lv_message.
STOP.
ENDTRY.
" No errors:
PERFORM output_message USING 'S'
'Proxy was saved.'(pws).
ENDFORM. "save_proxy
….and activation:
FORM activate_proxy USING io_proxy TYPE REF TO cl_proxy
iv_trreq TYPE trkorr .
DATA:
lt_objects TYPE sprx_log_t,
lt_log TYPE sprx_log_t,
ls_objects LIKE LINE OF lt_objects,
ls_log LIKE LINE OF lt_log,
lx_error TYPE REF TO cx_proxy_gen_error,
lv_message TYPE string.
TRY.
CALL METHOD io_proxy->activate
EXPORTING
activate_all = 'X'
deletion = 'X'
IMPORTING
activated_objects = lt_objects
log = lt_log
CHANGING
transport_number = iv_trreq.
CATCH cx_proxy_gen_error INTO lx_error.
lv_message = lx_error->if_message~get_text( ).
PERFORM output_message USING 'E'
lv_message.
STOP.
ENDTRY.
IF NOT lt_log[] IS INITIAL.
PERFORM output_message USING 'I'
'Activation log:'(alo).
LOOP AT lt_log INTO ls_log.
MESSAGE ID ls_log-msgid
TYPE ls_log-msgty
NUMBER ls_log-msgno
WITH ls_log-msgv1
ls_log-msgv2
ls_log-msgv3
ls_log-msgv4
INTO lv_message.
PERFORM output_message USING ls_log-msgty
lv_message.
ENDLOOP.
ENDIF.
IF NOT lt_objects[] IS INITIAL.
PERFORM output_message USING 'I'
'Activated objects:'(oli).
LOOP AT lt_objects INTO ls_objects.
MESSAGE ID ls_objects-msgid
TYPE ls_objects-msgty
NUMBER ls_objects-msgno
WITH ls_objects-msgv1
ls_objects-msgv2
ls_objects-msgv3
ls_objects-msgv4
INTO lv_message.
PERFORM output_message USING ls_objects-msgty
lv_message.
ENDLOOP.
ENDIF.
If you prefer not to keep “redundant” development objects, feel free to delete the proxy itself (without deletion of the subsequent objects 🙂 ). However, it should affect nothing if the proxy definition is transported to the production environment.
At the end of the day, you will get the DDIC structures which correspond to the ones described in an XML schema. Now using those structures your potential XML Simple Transformations will be really simple.
Hello,
Can you provide the entire code?
For example, the missing performs:
PERFORM get_transport_request CHANGING p_trrq. Â PERFORM get_file_name CHANGING p_xsdfn. "
PERFORM get_file_name CHANGING p_xsdfn.
and  maybe what is missing?
I need this for:
I'm working on a request for Poland to make an adjustment for a legal requirement. I installed an OSS note and made all the customizing and now we are facing problems with the XML. I know that the XML is the full responsibility of the customer, but maybe someone has an idea how can we create an XML to export the date from the 3 tables. (This requirement contain 3 tables(FIPLD_VAT_I, FIPLD_VAT_H, and FIPLD_VA_SUM) generated by the note and fulfilled by the report RPFIPL_SAFT with extraction). The idea is that on the official website with legal requirement we received a schema for JPK_VAT and it's XSD format. I need somehow to upload that schema into sap and fulfill it with data from those tables and export in XML.
Thanks in advance,
Vlad
Hi Kirill,
Could you please share complete code related to this report?
Kind regards,
Goran
Hello everyone,
As Kirill, I have the same situation, that is, no SAP PI, no SOAMANAGER.
I have the XSD file and if I understood corretly, the program mentioned generate DDIC from XDS file.
The Kirill text say about the dummy WSDL(is created automatically). I folow all the steps but, after execute de program I receive the message: --> Invalid URL xmldsig-core-schema.xsd <-- In XSD file line 3 (below) there is a call to a schemaLocation="./xmldsig-core-schema.xsd"/. This file is stored at the same directory.
I am not sure, but in debug mode I saw some access to Kernel Method to obtain the URL. My intention is not involve basis, but only create a DDIC with all structure table thru a ABAP program.
Does anyone achieved sucess in this hard work.
Thanks in advance.
Below, the tiny file XSD to generate DDIC in SAP.
Valter.
Hello all, first, thanks Kirill for your code! I imported this code and added the missing portions from other SAP standard code, here it is, use at own risk. For me it generated quite a number of DDIC structures from the XSD we have received. I have yet to see if it created all the ones needed. Use $TMP package initially to not impact an existing package or dev class. Also for me it did not save on transport probably because I used $TMP initially, and also got a proxy generation error. But it appears the proxy itself can be removed and not transported if needed.
*&---------------------------------------------------------------------*
*& report z_import_xml_schema
*&
*&---------------------------------------------------------------------*
*& this reports imports an xsd file and calls standard abap/4 proxy generation
*& methods to (re-)create ddic objects
*&---------------------------------------------------------------------*
REPORT z_import_xml_schema.
TYPE-POOLS: sprx,
trwbo.
CONSTANTS:
gc_lcl TYPE packname VALUE '$TMP'.
DATA:
go_proxy TYPE REF TO cl_proxy,
gv_xcontent TYPE xstring,
gv_wsdl TYPE xstring.
PARAMETERS:
p_xsdfn TYPE anyuri OBLIGATORY VALUE CHECK. "XML Schema file name
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-001.
PARAMETERS:
p_pckg TYPE packname VALUE CHECK DEFAULT gc_lcl, " Package
p_trrq TYPE trkorr VALUE CHECK, " Transport request
p_prfx TYPE prx_prefix OBLIGATORY DEFAULT 'Z', " Prefix
p_actv AS CHECKBOX DEFAULT 'X'. " Activate immediately
SELECTION-SCREEN END OF BLOCK b1.
* Create Transport request selection dialogue:
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_trrq.
PERFORM get_transport_request CHANGING p_trrq.
* File name selection dialogue:
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_xsdfn.
PERFORM get_file_name CHANGING p_xsdfn.
START-OF-SELECTION.
PERFORM upload_file USING p_xsdfn
CHANGING gv_xcontent.
PERFORM xsd2wsdl USING gv_xcontent
CHANGING gv_wsdl.
PERFORM init_proxy USING gv_wsdl
p_pckg
p_prfx
CHANGING go_proxy.
PERFORM save_proxy USING go_proxy.
IF NOT p_actv IS INITIAL.
PERFORM activate_proxy USING go_proxy
p_trrq.
ENDIF.
END-OF-SELECTION.
*&---------------------------------------------------------------------*
*& Form upload_file
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->IV_FILENAME text
* -->CV_XCONTENT text
*----------------------------------------------------------------------*
FORM upload_file USING iv_filename TYPE anyuri
CHANGING cv_xcontent TYPE xstring.
DATA: lo_slib_retriever TYPE REF TO if_slib_retriever,
lo_exception TYPE REF TO cx_root,
lv_fault TYPE xstring.
TRY.
lo_slib_retriever = cl_slib_entity_container=>create_retriever( ).
cv_xcontent = lo_slib_retriever->get_content( iv_filename ).
CATCH cx_slib INTO lo_exception.
PERFORM output_message USING 'E'
'Unable to read the file specified.'(urf).
STOP.
ENDTRY.
ENDFORM. "upload_file
*&---------------------------------------------------------------------*
*& Form xsd2wsdl
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->IV_XCONTENT text
* -->CV_WSDL text
*----------------------------------------------------------------------*
FORM xsd2wsdl USING iv_xcontent TYPE xstring
CHANGING cv_wsdl TYPE xstring.
DATA:
lv_message TYPE string,
lx_gen_error TYPE REF TO cx_proxy_gen_error.
TRY.
CALL METHOD cl_proxy_test_utils=>xsd2wsdl
EXPORTING
schema = iv_xcontent
RECEIVING
wsdl = cv_wsdl.
CATCH cx_proxy_gen_error INTO lx_gen_error .
lv_message = lx_gen_error->if_message~get_text( ).
PERFORM output_message USING 'E'
lv_message.
STOP.
ENDTRY.
ENDFORM. "xsd2wsdl
*&---------------------------------------------------------------------*
*& Form init_proxy
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->IV_WSDL text
* -->IV_PCKG text
* -->IV_PRAEFIX text
* -->CO_PROXY text
*----------------------------------------------------------------------*
FORM init_proxy USING iv_wsdl TYPE xstring
iv_pckg
iv_praefix
CHANGING co_proxy TYPE REF TO cl_proxy.
DATA:
lx_root TYPE REF TO cx_root,
lv_message TYPE string.
TRY.
CALL METHOD cl_proxy_test_utils=>wsdl2proxy
EXPORTING
wsdl = iv_wsdl
package = iv_pckg
praefix = iv_praefix
RECEIVING
proxy = co_proxy.
CATCH cx_proxy_gen_error INTO lx_root.
" LX_ROOT is checked below
CATCH cx_slib INTO lx_root.
" LX_ROOT is checked below
CATCH cx_sidl INTO lx_root.
" LX_ROOT is checked below
ENDTRY.
IF lx_root IS BOUND.
lv_message = lx_root->if_message~get_text( ).
PERFORM output_message USING 'E'
lv_message.
STOP.
ENDIF.
ENDFORM. "init_proxy
*&---------------------------------------------------------------------*
*& Form save_proxy
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->IO_PROXY text
*----------------------------------------------------------------------*
FORM save_proxy USING io_proxy TYPE REF TO cl_proxy.
DATA:
lx_error TYPE REF TO cx_proxy_gen_error,
lv_message TYPE string.
TRY.
CALL METHOD io_proxy->save
CHANGING
transport_number = p_trrq.
CATCH cx_proxy_gen_error INTO lx_error .
lv_message = lx_error->if_message~get_text( ).
PERFORM output_message USING 'E'
lv_message.
STOP.
ENDTRY.
" No errors:
PERFORM output_message USING 'S'
'Proxy was saved.'(pws).
ENDFORM. "save_proxy
*&---------------------------------------------------------------------*
*& Form activate_proxy
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->IO_PROXY text
* -->IV_TRREQ text
*----------------------------------------------------------------------*
FORM activate_proxy USING io_proxy TYPE REF TO cl_proxy
iv_trreq TYPE trkorr .
DATA:
lt_objects TYPE sprx_log_t,
lt_log TYPE sprx_log_t,
ls_objects LIKE LINE OF lt_objects,
ls_log LIKE LINE OF lt_log,
lx_error TYPE REF TO cx_proxy_gen_error,
lv_message TYPE string.
TRY.
CALL METHOD io_proxy->activate
EXPORTING
activate_all = 'X'
deletion = 'X'
IMPORTING
activated_objects = lt_objects
log = lt_log
CHANGING
transport_number = iv_trreq.
CATCH cx_proxy_gen_error INTO lx_error.
lv_message = lx_error->if_message~get_text( ).
PERFORM output_message USING 'E'
lv_message.
STOP.
ENDTRY.
IF NOT lt_log[] IS INITIAL.
PERFORM output_message USING 'I'
'Activation log:'(alo).
LOOP AT lt_log INTO ls_log.
MESSAGE ID ls_log-msgid
TYPE ls_log-msgty
NUMBER ls_log-msgno
WITH ls_log-msgv1
ls_log-msgv2
ls_log-msgv3
ls_log-msgv4
INTO lv_message.
PERFORM output_message USING ls_log-msgty
lv_message.
ENDLOOP.
ENDIF.
IF NOT lt_objects[] IS INITIAL.
PERFORM output_message USING 'I'
'Activated objects:'(oli).
LOOP AT lt_objects INTO ls_objects.
MESSAGE ID ls_objects-msgid
TYPE ls_objects-msgty
NUMBER ls_objects-msgno
WITH ls_objects-msgv1
ls_objects-msgv2
ls_objects-msgv3
ls_objects-msgv4
INTO lv_message.
PERFORM output_message USING ls_objects-msgty
lv_message.
ENDLOOP.
ENDIF.
ENDFORM. "activate_proxy
*&---------------------------------------------------------------------*
*& Form OUTPUT_MESSAGE
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_0116 text
* -->P_0117 text
*----------------------------------------------------------------------*
FORM output_message USING i_msg
i_text.
WRITE : / i_msg, i_text.
ENDFORM. " OUTPUT_MESSAGE
*&---------------------------------------------------------------------*
*& Form GET_FILE_NAME
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* <--P_P_XSDFN text
*----------------------------------------------------------------------*
FORM get_file_name CHANGING filename.
DATA:
l_rc TYPE i,
l_action TYPE i,
l_file_table TYPE filetable,
l_file TYPE LINE OF filetable,
l_title TYPE string.
l_title = 'File name'(001).
CALL METHOD cl_gui_frontend_services=>file_open_dialog
EXPORTING
window_title = l_title
multiselection = space
CHANGING
file_table = l_file_table
rc = l_rc
user_action = l_action
EXCEPTIONS
file_open_dialog_failed = 1
cntl_error = 2
error_no_gui = 3
not_supported_by_gui = 4
OTHERS = 5.
IF sy-subrc = 0 AND l_rc = 1 AND l_action = cl_gui_frontend_services=>action_ok.
READ TABLE l_file_table INDEX 1 INTO l_file.
filename = l_file-filename.
ENDIF.
ENDFORM. " GET_FILE_NAME
*&---------------------------------------------------------------------*
*& Form GET_TRANSPORT_REQUEST
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* <--transport text
*----------------------------------------------------------------------*
FORM get_transport_request CHANGING transport.
DATA: lv_len TYPE n,
lv_trfunction LIKE e070-trfunction,
ls_user TYPE trwbo_user,
lt_users TYPE trwbo_users,
ls_new_request TYPE trwbo_request_header.
CALL FUNCTION 'TR_POPUP_SELECT_REQUEST_TYPE'
EXPORTING
iv_trfunctions = 'KWTCEO' "all transport types
iv_title = 'Create transport'
IMPORTING
ev_trfunction = lv_trfunction
EXCEPTIONS
action_aborted_by_user = 1.
IF sy-subrc <> 0.
PERFORM send_current_message USING 'S'.
EXIT.
ENDIF.
IF lv_trfunction CA 'KW'.
ls_user-user = sy-uname.
APPEND ls_user TO lt_users.
ENDIF.
CALL FUNCTION 'TR_REQUEST_MODIFY'
EXPORTING
iv_action = 'CREA'
iv_new_request_type = lv_trfunction
it_users = lt_users
IMPORTING
es_new_request = ls_new_request
EXCEPTIONS
OTHERS = 1.
IF sy-subrc <> 0.
PERFORM send_current_message USING 'S'.
EXIT.
ENDIF.
transport = ls_new_request-trkorr.
CALL FUNCTION 'TR_PRESENT_REQUEST'
EXPORTING
iv_trkorr = ls_new_request-trkorr.
ENDFORM. " GET_TRANSPORT_REQUEST
*&---------------------------------------------------------------------*
*& Form SEND_CURRENT_MESSAGE
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->pv_mstyp text
*----------------------------------------------------------------------*
FORM send_current_message USING value(pv_mstyp) LIKE sy-msgty.
MESSAGE ID sy-msgid
TYPE pv_mstyp
NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDFORM. " SEND_CURRENT_MESSAGE