Saturday, October 16, 2010

Tres son multitud...XML, RegEx y Programación Dinámica


Como dije...aqui esta mi primer post sobre ABAP luego de mucho tiempo -:)

Como ya saben...soy un fanatico del RegEx o Expresiones Regulares y trato de utilizarlos cada vez que puedo. Herramienta matemática con RegEx y JavaScript.

Hace un par de semanas tuve que rehacer un programa hecho por otra persona, que leia un XML y creaba IDOCs con esa informacion...al ser un XML simple, pense que era un buen candidato para RegEx...asi que puse manos a la obra y el programa quedo excelente -;)

Claro, para efectos del blog tuve que crear un ejemplo nuevo que reflejara todos los componentes que utilice.

Entonces, lo primero es que crear un XML con este formato...


Luego, aqui tenemos el codigo fuente...


*&---------------------------------------------------------------------*
*& Report ZDUMMY *
*&---------------------------------------------------------------------*
REPORT ZDUMMY NO STANDARD PAGE HEADING.

*=====================================================*
* DECLARACION DE TYPES *
*=====================================================*
TYPES: BEGIN OF TY_FIELDS,
FIELD TYPE STRING,
END OF TY_FIELDS.

*=====================================================*
* DECLARACION DE VARIABLES *
*=====================================================*
DATA: DATA_TAB TYPE TABLE_OF_STRINGS,
T_FILETAB TYPE FILETABLE,
W_FILE_IN TYPE STRING,
RESULT_TAB TYPE MATCH_RESULT_TAB,
T_RESULTS TYPE MATCH_RESULT_TAB,
W_SUBRC TYPE SY-SUBRC,
SIZE TYPE I,
AUX TYPE STRING,
OFF TYPE I,
LEN TYPE I,
L_TABIX TYPE SY-TABIX,
L_LINES TYPE I,
L_STRING TYPE STRING,
T_FIELDS TYPE STANDARD TABLE OF TY_FIELDS,
DATAREF TYPE REF TO DATA,
NEW_LINE TYPE REF TO DATA,
IT_FIELDCATALOG TYPE LVC_T_FCAT,
WA_FCAT TYPE LVC_S_FCAT.

FIELD-SYMBOLS: <FS_FILETAB> LIKE LINE OF T_FILETAB,
<FS_RESULT_TAB> LIKE LINE OF RESULT_TAB,
<FS_RESULTS> LIKE LINE OF T_RESULTS,
<FS_DATA_TAB> LIKE LINE OF DATA_TAB,
<FS_FIELDS> LIKE LINE OF T_FIELDS,
<ROW> TYPE TABLE,
<FS_ROW> TYPE ANY,
<FS_ANY> TYPE ANY,
<L_LINE> TYPE ANY.

*=====================================================*
* SELECTION-SCREEN *
*=====================================================*
SELECTION-SCREEN BEGIN OF BLOCK TEST WITH FRAME.
PARAMETERS:
FILE_IN LIKE RLGRAP-FILENAME.
SELECTION-SCREEN END OF BLOCK TEST.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR FILE_IN.
CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG
EXPORTING
WINDOW_TITLE = 'Seleccionar archivo'
DEFAULT_FILENAME = '*.*'
FILE_FILTER = '*.*'
CHANGING
FILE_TABLE = T_FILETAB
RC = W_SUBRC.

READ TABLE T_FILETAB INDEX 1
ASSIGNING <FS_FILETAB>.
FILE_IN = <FS_FILETAB>.
W_FILE_IN = FILE_IN.

IF FILE_IN IS INITIAL.
EXIT.
ENDIF.

CLEAR T_FILETAB.
REFRESH T_FILETAB.

*=====================================================*
* START-OF-SELECTION *
*=====================================================*
START-OF-SELECTION.

CALL METHOD CL_GUI_FRONTEND_SERVICES=>GUI_UPLOAD
EXPORTING
FILENAME = W_FILE_IN
FILETYPE = 'DAT'
IMPORTING
FILELENGTH = SIZE
CHANGING
DATA_TAB = DATA_TAB.

LOOP AT DATA_TAB ASSIGNING <FS_DATA_TAB>.
FIND REGEX '<[a-zA-Z][^>]*>\S' IN <FS_DATA_TAB>.
IF SY-SUBRC NE 0.
CONTINUE.
ENDIF.
FIND ALL OCCURRENCES OF REGEX '<[^>]+>[^<]*</[^>]+>' IN <FS_DATA_TAB> RESULTS T_RESULTS.
LOOP AT T_RESULTS ASSIGNING <FS_RESULTS>.
AUX = <FS_DATA_TAB>+<FS_RESULTS>-OFFSET(<FS_RESULTS>-LENGTH).
FIND REGEX '[a-zA-Z\/][^>]*' IN AUX MATCH OFFSET OFF MATCH LENGTH LEN.
READ TABLE T_FIELDS ASSIGNING <FS_FIELDS>
WITH KEY FIELD = AUX+OFF(LEN).
IF SY-SUBRC NE 0 OR NOT <FS_FIELDS> IS ASSIGNED.
APPEND INITIAL LINE TO T_FIELDS ASSIGNING <FS_FIELDS>.
<FS_FIELDS>-FIELD = AUX+OFF(LEN).
ENDIF.
ENDLOOP.
ENDLOOP.

LOOP AT T_FIELDS ASSIGNING <FS_FIELDS>.
WA_FCAT-FIELDNAME = <FS_FIELDS>-FIELD.
WA_FCAT-REF_TABLE = 'PERF_STRING_STRUCT'.
WA_FCAT-REF_FIELD = 'DATA'.
APPEND WA_FCAT TO IT_FIELDCATALOG.
ENDLOOP.

CALL METHOD CL_ALV_TABLE_CREATE=>CREATE_DYNAMIC_TABLE
EXPORTING
IT_FIELDCATALOG = IT_FIELDCATALOG
IMPORTING
EP_TABLE = DATAREF
EXCEPTIONS
GENERATE_SUBPOOL_DIR_FULL = 1
OTHERS = 2.

ASSIGN DATAREF->* TO <ROW>.
CREATE DATA NEW_LINE LIKE LINE OF <ROW>.
ASSIGN NEW_LINE->* TO <L_LINE>.

LOOP AT DATA_TAB ASSIGNING <FS_DATA_TAB>.
FIND REGEX '<[a-zA-Z][^>]*>\S' IN <FS_DATA_TAB>.
IF SY-SUBRC NE 0.
CONTINUE.
ENDIF.
FIND ALL OCCURRENCES OF REGEX '<[^>]+>[^<]*</[^>]+>' IN <FS_DATA_TAB> RESULTS T_RESULTS.
LOOP AT T_RESULTS ASSIGNING <FS_RESULTS>.
AUX = <FS_DATA_TAB>+<FS_RESULTS>-OFFSET(<FS_RESULTS>-LENGTH).
FIND REGEX '[a-zA-Z\/][^>]*' IN AUX MATCH OFFSET OFF MATCH LENGTH LEN.
CONCATENATE '<L_LINE>-' AUX+OFF(LEN) INTO L_STRING.
REPLACE ALL OCCURRENCES OF REGEX '<[a-zA-Z\/][^>]*>' IN AUX WITH SPACE.
ASSIGN (L_STRING) TO <FS_ANY>.
<FS_ANY> = AUX.
ENDLOOP.
INSERT <L_LINE> INTO TABLE <ROW>.
ENDLOOP.

DESCRIBE TABLE IT_FIELDCATALOG LINES L_LINES.

LOOP AT <ROW> ASSIGNING <L_LINE>.
CLEAR L_TABIX.
DO L_LINES TIMES.
L_TABIX = L_TABIX + 1.
ASSIGN COMPONENT L_TABIX OF STRUCTURE <L_LINE> TO <FS_ROW>.
WRITE:/ <FS_ROW>.
ENDDO.
SKIP 1.
ENDLOOP.

El resultado seria...


Ahora...una pequenha explicacion...

* Utilizo el RegEx para poder leer los campos del XML y generar una tabla interna dinamica.
* Utilizo el RegEx nuevamente para poder llenar la tabla interna dinamica con los valores de los campos del XML.
* Utilizo programacion dinamica para poder imprimir los valores que hemos leido del XML.

Para que despues no vayan a criticarme...el XML tiene que tener un formato como el que puesto en el ejemplo...si tiene otro formato (cada TAG en una linea), este codigo no va a funcionar...habria que modificar el codigo un poco...asi que no...el codigo no sirve para leer cualquier XML que tengan en frente...sino como dije al inicio, para leer XML's simples y concretos.

Saludos,

Blag.

1 comment:

Manu said...

Espero tu visita a http://manutic.blogspot.com