SAPфорум.RU https://sapboard.ru/forum/ |
|
Генерация DOCX ABAPом. https://sapboard.ru/forum/viewtopic.php?f=13&t=82570 |
Страница 1 из 1 |
Автор: | Брат Мигель [ Вт, май 28 2013, 10:27 ] |
Заголовок сообщения: | Генерация DOCX ABAPом. |
Всем привет! Никак не доходили руки довести до рабочей версии свою поделку, но вроде как получилось. Ниже класс генерации отчета в формате DOCX средствами АБАП кода. Плюсы и минусы такого подхода описывать не имеет смысла, всем и так понятно. Если будут ошибки пишите, оперативно не исправлю, как будет возможность сделаю. Если вы нашли и поправили баг, буду вам благодарен. Сделал сразу с программой примером ее использования. Здесь после кода программы идет файл 1.docx, который надо скопировать в 'c:\temp'. Готовый файл упадет туда же с именем 3.docx. Code: *&---------------------------------------------------------------------*
*& Report ZHCM_TEST *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT zhcm_test. *----------------------------------------------------------------------* * CLASS lcl_docx DEFINITION *----------------------------------------------------------------------* * Поделка: Братковский Михаил можно просто Брат Мигель * версия один.и все нули * * Класс генерации отчетов в формате DOCX * при создании класса на вход передается строка xstring, содержащая * шаблон файла docx. * формат объявления полей в шаблоне следующий: * 1. если это не табличное поле, то оно должно начинаться на #0 * 2. если это поле таблицы, то оно должно начинантсья на #1 - #9, * где 1-9 значения параметра iv_table. * 3. После №0-№9 идет наименование поля. * 4. После наименования поля идет #. * Например: поле для простой замены #0DATE# * ВАЖНО! Все поле надо вписывать за один раз (без редактирования), * Если редактировать пол частично, * то почему-то текст развивается на разные теги * * 5. строка таблицы 1-9 может состоять из множества строк в шаблоне, * 6. перед внесением данных для новой строки табличной части, необходимо * вызывать метод new_line (для полей простой замены это не требуется). * 7. методы внесения данных (методы подходят для внесения любого поля): * 8. add_field - добавляет для заполнения одно поле. * 9. add_structure - добавляет все поля структуры * 10. add_table - добавляет все строки по всей структуре * 11. процесс заполнения осуществляется методом fill_data * 12. получения результирующего отчета - get_document * * что надо доделать: причесать код программы, добавить кучу проверок, * добавить преобразование полей согласно типа *----------------------------------------------------------------------* CLASS lcl_docx DEFINITION. PUBLIC SECTION. METHODS new_line. METHODS constructor IMPORTING string TYPE xstring. METHODS add_field IMPORTING iv_table TYPE string DEFAULT '0' iv_field TYPE string iv_value TYPE any. METHODS get_document RETURNING value(rv_string) TYPE xstring. METHODS clear_field_value. METHODS fill_data. METHODS clear_used_blocks. METHODS add_structure IMPORTING iv_table TYPE string is_data TYPE any. METHODS add_table IMPORTING iv_table TYPE string it_data TYPE any. PRIVATE SECTION. TYPE-POOLS: ixml, abap. CLASS cl_ixml DEFINITION LOAD. TYPES: BEGIN OF ts_vfields, number TYPE i, table TYPE num1, fieldname TYPE string, fieldrep TYPE string, value TYPE string, END OF ts_vfields. TYPES: tt_vfields TYPE TABLE OF ts_vfields WITH NON-UNIQUE KEY number table fieldname. TYPES: BEGIN OF ts_nodes_tables, table TYPE num1, gid TYPE i, END OF ts_nodes_tables. TYPES: tt_nodes_tables TYPE TABLE OF ts_nodes_tables WITH NON-UNIQUE KEY table. TYPES: BEGIN OF ts_nodes_fields, table TYPE num1, gid TYPE i, index TYPE i, END OF ts_nodes_fields. TYPES: tt_nodes_fields TYPE TABLE OF ts_nodes_fields WITH NON-UNIQUE KEY table. TYPES: BEGIN OF ts_number_tables, number TYPE i, table TYPE num1, END OF ts_number_tables. TYPES: tt_number_tables TYPE TABLE OF ts_number_tables WITH NON-UNIQUE KEY number table. TYPES: BEGIN OF ts_table_fields, table TYPE num1, fieldname TYPE string, fieldtype TYPE char1, END OF ts_table_fields. TYPES: tt_table_fields TYPE TABLE OF ts_table_fields WITH NON-UNIQUE KEY table fieldname. CLASS-DATA: gr_document TYPE REF TO if_ixml_document ,gr_istream TYPE REF TO if_ixml_istream ,gr_ixml TYPE REF TO if_ixml ,gr_ostream TYPE REF TO if_ixml_ostream ,gr_parser TYPE REF TO if_ixml_parser ,gr_renderer TYPE REF TO if_ixml_renderer ,gr_stream_factory TYPE REF TO if_ixml_stream_factory ,gr_zipper TYPE REF TO cl_abap_zip ,gt_fields_val TYPE tt_vfields ,gt_nodes_fields TYPE tt_nodes_fields ,gt_nodes_tables TYPE tt_nodes_tables ,gt_number_tables TYPE tt_number_tables ,gt_table_fields TYPE tt_table_fields ,gv_document TYPE xstring ,gv_number TYPE i. METHODS set_field_value IMPORTING ir_node TYPE REF TO if_ixml_node iv_number TYPE i. METHODS check_fields. METHODS check_tables. METHODS check_report. ENDCLASS. "lcl_docx DEFINITION *----------------------------------------------------------------------* * CLASS lcl_docx IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_docx IMPLEMENTATION. METHOD new_line. gv_number = gv_number + 1. ENDMETHOD. "NEW_LINE METHOD constructor. CREATE OBJECT gr_zipper. gr_zipper->load( string ). gr_zipper->get( EXPORTING name = 'word/document.xml' IMPORTING content = gv_document ). gr_ixml = cl_ixml=>create( ). gr_stream_factory = gr_ixml->create_stream_factory( ). gr_istream = gr_stream_factory->create_istream_xstring( gv_document ). gr_document = gr_ixml->create_document( ). gr_parser = gr_ixml->create_parser( stream_factory = gr_stream_factory istream = gr_istream document = gr_document ). gr_parser->parse( ). gv_number = 1. ENDMETHOD. "constructor METHOD add_field. DATA: ls_fields_val TYPE ts_vfields, ls_number_tables TYPE ts_number_tables. IF iv_table = '0'. ls_number_tables-number = ls_fields_val-number = 1. ELSE. ls_number_tables-number = ls_fields_val-number = gv_number. ENDIF. ls_number_tables-table = ls_fields_val-table = iv_table. READ TABLE gt_number_tables WITH KEY number = gv_number table = iv_table BINARY SEARCH TRANSPORTING NO FIELDS. IF sy-subrc IS NOT INITIAL. APPEND ls_number_tables TO gt_number_tables. ENDIF. ls_fields_val-fieldname = iv_field. CONCATENATE '#' iv_table iv_field '#' INTO ls_fields_val-fieldrep. ls_fields_val-value = iv_value. APPEND ls_fields_val TO gt_fields_val. ENDMETHOD. "add_field METHOD get_document. DATA: lv_document TYPE xstring. gr_ostream = gr_stream_factory->create_ostream_xstring( string = lv_document ). gr_renderer = gr_ixml->create_renderer( ostream = gr_ostream document = gr_document ). gr_renderer->render( ). gr_zipper->delete( EXPORTING name = 'word/document.xml' ). gr_zipper->add( EXPORTING name = 'word/document.xml' content = lv_document ). rv_string = gr_zipper->save( ). ENDMETHOD. "get_document METHOD clear_field_value. CLEAR: gt_fields_val[]. gv_number = 1. ENDMETHOD. "CLEAR_FIELD_VALUE METHOD fill_data. DATA: lr_cnode TYPE REF TO if_ixml_node. DATA: lr_nnode TYPE REF TO if_ixml_node. DATA: lr_pnode TYPE REF TO if_ixml_node. DATA: lr_fnode TYPE REF TO if_ixml_node, lr_ffilter TYPE REF TO if_ixml_node_filter, lr_fiterator TYPE REF TO if_ixml_node_iterator. DATA: ls_field_val TYPE ts_vfields, ls_nodes_tables TYPE ts_nodes_tables, ls_number_tables TYPE ts_number_tables. DATA: lv_number TYPE i, lv_gid TYPE i, lv_index TYPE i, lv_tabix TYPE i. me->check_report( ). SORT gt_fields_val BY number. DO gv_number TIMES. lv_number = sy-index. READ TABLE gt_number_tables WITH KEY number = lv_number BINARY SEARCH TRANSPORTING NO FIELDS. IF sy-subrc IS INITIAL. lv_tabix = sy-tabix. ELSE. lv_tabix = 1. ENDIF. LOOP AT gt_number_tables FROM lv_tabix INTO ls_number_tables. IF ls_number_tables-number NE lv_number. EXIT. ENDIF. LOOP AT gt_nodes_tables INTO ls_nodes_tables WHERE table = ls_number_tables-table. IF ls_nodes_tables-table > '0'. lr_cnode = gr_document->find_from_gid( ls_nodes_tables-gid ). lr_nnode = lr_cnode->clone( ). lr_pnode = lr_cnode->get_parent( ). lr_pnode->append_child( lr_nnode ). lv_gid = lr_nnode->get_gid( ). lr_ffilter = lr_nnode->create_filter_name( name = '#text' ). lr_fiterator = lr_nnode->create_iterator_filtered( lr_ffilter ). lr_fnode = lr_fiterator->get_next( ). WHILE lr_fnode IS NOT INITIAL. lv_index = sy-index. READ TABLE gt_nodes_fields WITH KEY table = ls_nodes_tables-table gid = ls_nodes_tables-gid index = lv_index TRANSPORTING NO FIELDS. IF sy-subrc IS INITIAL. me->set_field_value( ir_node = lr_fnode iv_number = lv_number ). ENDIF. lr_fnode = lr_fiterator->get_next( ). ENDWHILE. FREE: lr_ffilter, lr_fiterator. ELSE. lr_fnode = gr_document->find_from_gid( ls_nodes_tables-gid ). me->set_field_value( ir_node = lr_fnode iv_number = lv_number ). ENDIF. ENDLOOP. ENDLOOP. ENDDO. clear_used_blocks( ). clear_field_value( ). ENDMETHOD. "fill_data METHOD clear_used_blocks. DATA: lr_node TYPE REF TO if_ixml_node. DATA: ls_nodes_tables TYPE ts_nodes_tables. LOOP AT gt_nodes_tables INTO ls_nodes_tables WHERE table > '0'. lr_node = gr_document->find_from_gid( ls_nodes_tables-gid ). IF lr_node IS NOT INITIAL. lr_node->remove_node( ). ENDIF. ENDLOOP. ENDMETHOD. "clear_used_blocks METHOD add_structure. DATA: lr_struc_descr TYPE REF TO cl_abap_structdescr, lt_fields TYPE ddfields, ls_fields TYPE LINE OF ddfields. DATA: lt_components TYPE abap_compdescr_tab, ls_components TYPE LINE OF abap_compdescr_tab. DATA: lv_field TYPE string, lv_value TYPE string. FIELD-SYMBOLS: <value> TYPE any. new_line( ). lr_struc_descr ?= cl_abap_structdescr=>describe_by_data( is_data ). LOOP AT lr_struc_descr->components INTO ls_components. ASSIGN COMPONENT sy-tabix OF STRUCTURE is_data TO <value>. lv_field = ls_components-name."ls_fields-fieldname. lv_value = <value>. add_field( iv_table = iv_table iv_field = lv_field iv_value = lv_value ). ENDLOOP. ENDMETHOD. "add_structure METHOD add_table. FIELD-SYMBOLS: <table> TYPE ANY TABLE, <structure> TYPE any. ASSIGN it_data TO <table>. LOOP AT <table> ASSIGNING <structure>. add_structure( iv_table = iv_table is_data = <structure> ). ENDLOOP. ENDMETHOD. "add_table METHOD set_field_value. DATA: ls_fields_val TYPE ts_vfields. DATA: lv_value TYPE string, lv_count TYPE i, lv_tabix TYPE i. lv_value = ir_node->get_value( ). *< loop optimize в таком виде loop работает на порядок быстрее, но таблица должна быть отсортирована по ключу READ TABLE gt_fields_val WITH KEY number = iv_number BINARY SEARCH TRANSPORTING NO FIELDS. IF sy-subrc IS INITIAL. lv_tabix = sy-tabix. ELSE. lv_tabix = 1. ENDIF. LOOP AT gt_fields_val FROM lv_tabix INTO ls_fields_val. IF ls_fields_val-number NE iv_number. EXIT. ENDIF. REPLACE ls_fields_val-fieldrep IN lv_value WITH ls_fields_val-value. IF sy-subrc = 0. lv_count = 1. ENDIF. ENDLOOP. *> loop optimize IF lv_count = 1. ir_node->set_value( lv_value ). ENDIF. ENDMETHOD. "set_field_value METHOD check_fields. DATA: lr_cnode TYPE REF TO if_ixml_node. DATA: lr_filter TYPE REF TO if_ixml_node_filter, lr_iterator TYPE REF TO if_ixml_node_iterator. DATA: ls_nodes_fields TYPE ts_nodes_fields, ls_nodes_tables TYPE ts_nodes_tables. DATA: lv_gid TYPE i, lv_num TYPE num1, lv_count TYPE i, lv_value TYPE string, lv_tname TYPE text2 VALUE '#0'. lr_filter = gr_document->create_filter_name( name = '#text'). lr_iterator = gr_document->create_iterator_filtered( lr_filter ). lr_cnode = lr_iterator->get_next( ). WHILE lr_cnode IS NOT INITIAL. lv_gid = lr_cnode->get_gid( ). lv_value = lr_cnode->get_value( ). FIND lv_tname IN lv_value MATCH COUNT lv_count. IF lv_count > 0. READ TABLE gt_nodes_tables WITH KEY table = 0 gid = lv_gid TRANSPORTING NO FIELDS. IF sy-subrc IS NOT INITIAL. ls_nodes_tables-table = 0. ls_nodes_tables-gid = lv_gid. APPEND ls_nodes_tables TO gt_nodes_tables. ENDIF. ENDIF. lr_cnode = lr_iterator->get_next( ). ENDWHILE. ENDMETHOD. "check_fields METHOD check_tables. DATA: lr_tnode TYPE REF TO if_ixml_node, lr_fnode TYPE REF TO if_ixml_node, lr_tfilter TYPE REF TO if_ixml_node_filter, lr_ffilter TYPE REF TO if_ixml_node_filter, lr_titerator TYPE REF TO if_ixml_node_iterator, lr_fiterator TYPE REF TO if_ixml_node_iterator. DATA: ls_nodes_fields TYPE ts_nodes_fields, ls_nodes_tables TYPE ts_nodes_tables. DATA: lv_gid TYPE i, lv_index TYPE i, lv_num TYPE num1, lv_count TYPE i, lv_value TYPE string, lv_tname TYPE text2. lr_tfilter = gr_document->create_filter_name( name = 'tr' namespace = 'w' ). lr_titerator = gr_document->create_iterator_filtered( lr_tfilter ). lr_tnode = lr_titerator->get_next( ). WHILE lr_tnode IS NOT INITIAL. lv_gid = lr_tnode->get_gid( ). * me->check_fields( lv_gid ). lr_ffilter = lr_tnode->create_filter_name( name = '#text' ). lr_fiterator = lr_tnode->create_iterator_filtered( lr_ffilter ). lr_fnode = lr_fiterator->get_next( ). WHILE lr_fnode IS NOT INITIAL. CLEAR lv_count. lv_num = 1. ls_nodes_fields-index = sy-index. ls_nodes_fields-gid = lv_gid. lv_value = lr_fnode->get_value( ). DO 10 TIMES. CONCATENATE '#' lv_num INTO lv_tname. FIND lv_tname IN lv_value MATCH COUNT lv_count. IF lv_count > 0. ls_nodes_fields-table = lv_num. APPEND ls_nodes_fields TO gt_nodes_fields. EXIT. ENDIF. lv_num = lv_num + 1. ENDDO. IF lv_count > 0. READ TABLE gt_nodes_tables WITH KEY table = lv_num gid = lv_gid TRANSPORTING NO FIELDS. IF sy-subrc IS NOT INITIAL. ls_nodes_tables-table = lv_num. ls_nodes_tables-gid = lv_gid. APPEND ls_nodes_tables TO gt_nodes_tables. ENDIF. ENDIF. lr_fnode = lr_fiterator->get_next( ). ENDWHILE. FREE: lr_ffilter, lr_fiterator, lr_fnode. lr_tnode = lr_titerator->get_next( ). ENDWHILE. ENDMETHOD. "check_fields METHOD check_report. me->check_tables( ). me->check_fields( ). ENDMETHOD. "check_tables ENDCLASS. "lcl_docx IMPLEMENTATION PARAMETERS p_file TYPE text250 DEFAULT 'c:\temp\1.docx'. DATA: l_data_xml TYPE xstring. DATA: l_filename TYPE string. START-OF-SELECTION. l_filename = p_file. TRY. l_data_xml = cl_openxml_helper=>load_local_file( l_filename ). CATCH cx_openxml_not_found. ENDTRY. DATA: gr_docx TYPE REF TO lcl_docx. CREATE OBJECT gr_docx EXPORTING string = l_data_xml. gr_docx->add_field( iv_field = 'DATE1' iv_value = '01.01.2013'). gr_docx->add_field( iv_field = 'FIO' iv_value = 'Иванов Иван Иванович'). DO 1000 TIMES. gr_docx->new_line( ). gr_docx->add_field( iv_table = '1' iv_field = 'DATA' iv_value = 'text1 table1'). gr_docx->add_field( iv_table = '1' iv_field = 'NUM' iv_value = sy-index ). gr_docx->new_line( ). gr_docx->add_field( iv_table = '1' iv_field = 'DATA' iv_value = 'text2 table1'). gr_docx->add_field( iv_table = '1' iv_field = 'NUM' iv_value = '1.2.'). gr_docx->new_line( ). gr_docx->add_field( iv_table = '2' iv_field = 'DATA' iv_value = 'text1 table2'). gr_docx->add_field( iv_table = '2' iv_field = 'NUM' iv_value = '2.1.'). gr_docx->new_line( ). gr_docx->add_field( iv_table = '2' iv_field = 'DATA' iv_value = 'text2 table2'). gr_docx->add_field( iv_table = '2' iv_field = 'NUM' iv_value = '2.2.'). gr_docx->new_line( ). gr_docx->add_field( iv_table = '1' iv_field = 'DATA' iv_value = 'text3 table1'). gr_docx->add_field( iv_table = '1' iv_field = 'NUM' iv_value = '1.3.'). ENDDO. gr_docx->fill_data( ). l_data_xml = gr_docx->get_document( ). cl_openxml_helper=>store_local_file( im_file_name = 'c:\temp\3.docx' im_data = l_data_xml ). |
Автор: | Fugitive [ Вт, май 28 2013, 10:58 ] |
Заголовок сообщения: | Re: Генерация DOCX ABAPом. |
На каких объемах данных тестировали? Классы IXML весьма тормознутые. |
Автор: | Брат Мигель [ Вт, май 28 2013, 11:03 ] |
Заголовок сообщения: | Re: Генерация DOCX ABAPом. |
Fugitive написал(а): На каких объемах данных тестировали? Классы IXML весьма тормознутые. В примере генерируется 230 страничный документ. Время генерации 8 секунд. |
Автор: | homoSAPience [ Вт, май 28 2013, 11:19 ] |
Заголовок сообщения: | Re: Генерация DOCX ABAPом. |
Брат Мигель написал: Fugitive написал(а): На каких объемах данных тестировали? Классы IXML весьма тормознутые. В примере генерируется 230 страничный документ. Время генерации 8 секунд. |
Автор: | weise [ Вт, май 28 2013, 11:24 ] |
Заголовок сообщения: | Re: Генерация DOCX ABAPом. |
Классно, очень благодарен! Обязательно попробую использовать. Кстати, вы не пробовали abap2docx, какие самые принципиальные отличия от него? |
Автор: | Брат Мигель [ Вт, май 28 2013, 11:27 ] |
Заголовок сообщения: | Re: Генерация DOCX ABAPом. |
homoSAPience написал(а): Брат Мигель, почему с ворда-то начали? Ну мысль была такая, что генерировать документы и приказы можно было бы: в фоне, сохранять журнал отчетов вместе с самим файлом ну и т.д. Если говорить об экселе, у него посложнее структура файла. Да и для экселя наверняка есть уже что-то подобное. |
Автор: | Брат Мигель [ Вт, май 28 2013, 13:44 ] |
Заголовок сообщения: | Re: Генерация DOCX ABAPом. |
weise написал(а): Кстати, вы не пробовали abap2docx, какие самые принципиальные отличия от него? Честно говоря не видел, может и зря наколхозил . |
Автор: | weise [ Вт, май 28 2013, 16:58 ] |
Заголовок сообщения: | Re: Генерация DOCX ABAPом. |
Нет, точно не зря. Тут все довольно компактно и понятно, а там не самый дружелюбный интерфейс, хотя развиваются давно. |
Автор: | Benoni [ Чт, ноя 11 2021, 15:30 ] |
Заголовок сообщения: | Re: Генерация DOCX ABAPом. |
Это задублированное сообщение, админы, удалите, пожалуйста |
Автор: | Benoni [ Чт, ноя 11 2021, 15:31 ] |
Заголовок сообщения: | Re: Генерация DOCX ABAPом. |
Привет, Брат Мигель! А можешь перезалить файлик с 1.docx, хотел поизучать твою программу? Спасибо! Брат Мигель написал: Всем привет!
Никак не доходили руки довести до рабочей версии свою поделку, но вроде как получилось. Ниже класс генерации отчета в формате DOCX средствами АБАП кода. Плюсы и минусы такого подхода описывать не имеет смысла, всем и так понятно. Если будут ошибки пишите, оперативно не исправлю, как будет возможность сделаю. Если вы нашли и поправили баг, буду вам благодарен. Сделал сразу с программой примером ее использования. Здесь после кода программы идет файл 1.docx, который надо скопировать в 'c:\temp'. Готовый файл упадет туда же с именем 3.docx. Code: *&---------------------------------------------------------------------* *& Report ZHCM_TEST *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT zhcm_test. *----------------------------------------------------------------------* * CLASS lcl_docx DEFINITION *----------------------------------------------------------------------* * Поделка: Братковский Михаил можно просто Брат Мигель * версия один.и все нули * * Класс генерации отчетов в формате DOCX * при создании класса на вход передается строка xstring, содержащая * шаблон файла docx. * формат объявления полей в шаблоне следующий: * 1. если это не табличное поле, то оно должно начинаться на #0 * 2. если это поле таблицы, то оно должно начинантсья на #1 - #9, * где 1-9 значения параметра iv_table. * 3. После №0-№9 идет наименование поля. * 4. После наименования поля идет #. * Например: поле для простой замены #0DATE# * ВАЖНО! Все поле надо вписывать за один раз (без редактирования), * Если редактировать пол частично, * то почему-то текст развивается на разные теги * * 5. строка таблицы 1-9 может состоять из множества строк в шаблоне, * 6. перед внесением данных для новой строки табличной части, необходимо * вызывать метод new_line (для полей простой замены это не требуется). * 7. методы внесения данных (методы подходят для внесения любого поля): * 8. add_field - добавляет для заполнения одно поле. * 9. add_structure - добавляет все поля структуры * 10. add_table - добавляет все строки по всей структуре * 11. процесс заполнения осуществляется методом fill_data * 12. получения результирующего отчета - get_document * * что надо доделать: причесать код программы, добавить кучу проверок, * добавить преобразование полей согласно типа *----------------------------------------------------------------------* CLASS lcl_docx DEFINITION. PUBLIC SECTION. METHODS new_line. METHODS constructor IMPORTING string TYPE xstring. METHODS add_field IMPORTING iv_table TYPE string DEFAULT '0' iv_field TYPE string iv_value TYPE any. METHODS get_document RETURNING value(rv_string) TYPE xstring. METHODS clear_field_value. METHODS fill_data. METHODS clear_used_blocks. METHODS add_structure IMPORTING iv_table TYPE string is_data TYPE any. METHODS add_table IMPORTING iv_table TYPE string it_data TYPE any. PRIVATE SECTION. TYPE-POOLS: ixml, abap. CLASS cl_ixml DEFINITION LOAD. TYPES: BEGIN OF ts_vfields, number TYPE i, table TYPE num1, fieldname TYPE string, fieldrep TYPE string, value TYPE string, END OF ts_vfields. TYPES: tt_vfields TYPE TABLE OF ts_vfields WITH NON-UNIQUE KEY number table fieldname. TYPES: BEGIN OF ts_nodes_tables, table TYPE num1, gid TYPE i, END OF ts_nodes_tables. TYPES: tt_nodes_tables TYPE TABLE OF ts_nodes_tables WITH NON-UNIQUE KEY table. TYPES: BEGIN OF ts_nodes_fields, table TYPE num1, gid TYPE i, index TYPE i, END OF ts_nodes_fields. TYPES: tt_nodes_fields TYPE TABLE OF ts_nodes_fields WITH NON-UNIQUE KEY table. TYPES: BEGIN OF ts_number_tables, number TYPE i, table TYPE num1, END OF ts_number_tables. TYPES: tt_number_tables TYPE TABLE OF ts_number_tables WITH NON-UNIQUE KEY number table. TYPES: BEGIN OF ts_table_fields, table TYPE num1, fieldname TYPE string, fieldtype TYPE char1, END OF ts_table_fields. TYPES: tt_table_fields TYPE TABLE OF ts_table_fields WITH NON-UNIQUE KEY table fieldname. CLASS-DATA: gr_document TYPE REF TO if_ixml_document ,gr_istream TYPE REF TO if_ixml_istream ,gr_ixml TYPE REF TO if_ixml ,gr_ostream TYPE REF TO if_ixml_ostream ,gr_parser TYPE REF TO if_ixml_parser ,gr_renderer TYPE REF TO if_ixml_renderer ,gr_stream_factory TYPE REF TO if_ixml_stream_factory ,gr_zipper TYPE REF TO cl_abap_zip ,gt_fields_val TYPE tt_vfields ,gt_nodes_fields TYPE tt_nodes_fields ,gt_nodes_tables TYPE tt_nodes_tables ,gt_number_tables TYPE tt_number_tables ,gt_table_fields TYPE tt_table_fields ,gv_document TYPE xstring ,gv_number TYPE i. METHODS set_field_value IMPORTING ir_node TYPE REF TO if_ixml_node iv_number TYPE i. METHODS check_fields. METHODS check_tables. METHODS check_report. ENDCLASS. "lcl_docx DEFINITION *----------------------------------------------------------------------* * CLASS lcl_docx IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_docx IMPLEMENTATION. METHOD new_line. gv_number = gv_number + 1. ENDMETHOD. "NEW_LINE METHOD constructor. CREATE OBJECT gr_zipper. gr_zipper->load( string ). gr_zipper->get( EXPORTING name = 'word/document.xml' IMPORTING content = gv_document ). gr_ixml = cl_ixml=>create( ). gr_stream_factory = gr_ixml->create_stream_factory( ). gr_istream = gr_stream_factory->create_istream_xstring( gv_document ). gr_document = gr_ixml->create_document( ). gr_parser = gr_ixml->create_parser( stream_factory = gr_stream_factory istream = gr_istream document = gr_document ). gr_parser->parse( ). gv_number = 1. ENDMETHOD. "constructor METHOD add_field. DATA: ls_fields_val TYPE ts_vfields, ls_number_tables TYPE ts_number_tables. IF iv_table = '0'. ls_number_tables-number = ls_fields_val-number = 1. ELSE. ls_number_tables-number = ls_fields_val-number = gv_number. ENDIF. ls_number_tables-table = ls_fields_val-table = iv_table. READ TABLE gt_number_tables WITH KEY number = gv_number table = iv_table BINARY SEARCH TRANSPORTING NO FIELDS. IF sy-subrc IS NOT INITIAL. APPEND ls_number_tables TO gt_number_tables. ENDIF. ls_fields_val-fieldname = iv_field. CONCATENATE '#' iv_table iv_field '#' INTO ls_fields_val-fieldrep. ls_fields_val-value = iv_value. APPEND ls_fields_val TO gt_fields_val. ENDMETHOD. "add_field METHOD get_document. DATA: lv_document TYPE xstring. gr_ostream = gr_stream_factory->create_ostream_xstring( string = lv_document ). gr_renderer = gr_ixml->create_renderer( ostream = gr_ostream document = gr_document ). gr_renderer->render( ). gr_zipper->delete( EXPORTING name = 'word/document.xml' ). gr_zipper->add( EXPORTING name = 'word/document.xml' content = lv_document ). rv_string = gr_zipper->save( ). ENDMETHOD. "get_document METHOD clear_field_value. CLEAR: gt_fields_val[]. gv_number = 1. ENDMETHOD. "CLEAR_FIELD_VALUE METHOD fill_data. DATA: lr_cnode TYPE REF TO if_ixml_node. DATA: lr_nnode TYPE REF TO if_ixml_node. DATA: lr_pnode TYPE REF TO if_ixml_node. DATA: lr_fnode TYPE REF TO if_ixml_node, lr_ffilter TYPE REF TO if_ixml_node_filter, lr_fiterator TYPE REF TO if_ixml_node_iterator. DATA: ls_field_val TYPE ts_vfields, ls_nodes_tables TYPE ts_nodes_tables, ls_number_tables TYPE ts_number_tables. DATA: lv_number TYPE i, lv_gid TYPE i, lv_index TYPE i, lv_tabix TYPE i. me->check_report( ). SORT gt_fields_val BY number. DO gv_number TIMES. lv_number = sy-index. READ TABLE gt_number_tables WITH KEY number = lv_number BINARY SEARCH TRANSPORTING NO FIELDS. IF sy-subrc IS INITIAL. lv_tabix = sy-tabix. ELSE. lv_tabix = 1. ENDIF. LOOP AT gt_number_tables FROM lv_tabix INTO ls_number_tables. IF ls_number_tables-number NE lv_number. EXIT. ENDIF. LOOP AT gt_nodes_tables INTO ls_nodes_tables WHERE table = ls_number_tables-table. IF ls_nodes_tables-table > '0'. lr_cnode = gr_document->find_from_gid( ls_nodes_tables-gid ). lr_nnode = lr_cnode->clone( ). lr_pnode = lr_cnode->get_parent( ). lr_pnode->append_child( lr_nnode ). lv_gid = lr_nnode->get_gid( ). lr_ffilter = lr_nnode->create_filter_name( name = '#text' ). lr_fiterator = lr_nnode->create_iterator_filtered( lr_ffilter ). lr_fnode = lr_fiterator->get_next( ). WHILE lr_fnode IS NOT INITIAL. lv_index = sy-index. READ TABLE gt_nodes_fields WITH KEY table = ls_nodes_tables-table gid = ls_nodes_tables-gid index = lv_index TRANSPORTING NO FIELDS. IF sy-subrc IS INITIAL. me->set_field_value( ir_node = lr_fnode iv_number = lv_number ). ENDIF. lr_fnode = lr_fiterator->get_next( ). ENDWHILE. FREE: lr_ffilter, lr_fiterator. ELSE. lr_fnode = gr_document->find_from_gid( ls_nodes_tables-gid ). me->set_field_value( ir_node = lr_fnode iv_number = lv_number ). ENDIF. ENDLOOP. ENDLOOP. ENDDO. clear_used_blocks( ). clear_field_value( ). ENDMETHOD. "fill_data METHOD clear_used_blocks. DATA: lr_node TYPE REF TO if_ixml_node. DATA: ls_nodes_tables TYPE ts_nodes_tables. LOOP AT gt_nodes_tables INTO ls_nodes_tables WHERE table > '0'. lr_node = gr_document->find_from_gid( ls_nodes_tables-gid ). IF lr_node IS NOT INITIAL. lr_node->remove_node( ). ENDIF. ENDLOOP. ENDMETHOD. "clear_used_blocks METHOD add_structure. DATA: lr_struc_descr TYPE REF TO cl_abap_structdescr, lt_fields TYPE ddfields, ls_fields TYPE LINE OF ddfields. DATA: lt_components TYPE abap_compdescr_tab, ls_components TYPE LINE OF abap_compdescr_tab. DATA: lv_field TYPE string, lv_value TYPE string. FIELD-SYMBOLS: <value> TYPE any. new_line( ). lr_struc_descr ?= cl_abap_structdescr=>describe_by_data( is_data ). LOOP AT lr_struc_descr->components INTO ls_components. ASSIGN COMPONENT sy-tabix OF STRUCTURE is_data TO <value>. lv_field = ls_components-name."ls_fields-fieldname. lv_value = <value>. add_field( iv_table = iv_table iv_field = lv_field iv_value = lv_value ). ENDLOOP. ENDMETHOD. "add_structure METHOD add_table. FIELD-SYMBOLS: <table> TYPE ANY TABLE, <structure> TYPE any. ASSIGN it_data TO <table>. LOOP AT <table> ASSIGNING <structure>. add_structure( iv_table = iv_table is_data = <structure> ). ENDLOOP. ENDMETHOD. "add_table METHOD set_field_value. DATA: ls_fields_val TYPE ts_vfields. DATA: lv_value TYPE string, lv_count TYPE i, lv_tabix TYPE i. lv_value = ir_node->get_value( ). *< loop optimize в таком виде loop работает на порядок быстрее, но таблица должна быть отсортирована по ключу READ TABLE gt_fields_val WITH KEY number = iv_number BINARY SEARCH TRANSPORTING NO FIELDS. IF sy-subrc IS INITIAL. lv_tabix = sy-tabix. ELSE. lv_tabix = 1. ENDIF. LOOP AT gt_fields_val FROM lv_tabix INTO ls_fields_val. IF ls_fields_val-number NE iv_number. EXIT. ENDIF. REPLACE ls_fields_val-fieldrep IN lv_value WITH ls_fields_val-value. IF sy-subrc = 0. lv_count = 1. ENDIF. ENDLOOP. *> loop optimize IF lv_count = 1. ir_node->set_value( lv_value ). ENDIF. ENDMETHOD. "set_field_value METHOD check_fields. DATA: lr_cnode TYPE REF TO if_ixml_node. DATA: lr_filter TYPE REF TO if_ixml_node_filter, lr_iterator TYPE REF TO if_ixml_node_iterator. DATA: ls_nodes_fields TYPE ts_nodes_fields, ls_nodes_tables TYPE ts_nodes_tables. DATA: lv_gid TYPE i, lv_num TYPE num1, lv_count TYPE i, lv_value TYPE string, lv_tname TYPE text2 VALUE '#0'. lr_filter = gr_document->create_filter_name( name = '#text'). lr_iterator = gr_document->create_iterator_filtered( lr_filter ). lr_cnode = lr_iterator->get_next( ). WHILE lr_cnode IS NOT INITIAL. lv_gid = lr_cnode->get_gid( ). lv_value = lr_cnode->get_value( ). FIND lv_tname IN lv_value MATCH COUNT lv_count. IF lv_count > 0. READ TABLE gt_nodes_tables WITH KEY table = 0 gid = lv_gid TRANSPORTING NO FIELDS. IF sy-subrc IS NOT INITIAL. ls_nodes_tables-table = 0. ls_nodes_tables-gid = lv_gid. APPEND ls_nodes_tables TO gt_nodes_tables. ENDIF. ENDIF. lr_cnode = lr_iterator->get_next( ). ENDWHILE. ENDMETHOD. "check_fields METHOD check_tables. DATA: lr_tnode TYPE REF TO if_ixml_node, lr_fnode TYPE REF TO if_ixml_node, lr_tfilter TYPE REF TO if_ixml_node_filter, lr_ffilter TYPE REF TO if_ixml_node_filter, lr_titerator TYPE REF TO if_ixml_node_iterator, lr_fiterator TYPE REF TO if_ixml_node_iterator. DATA: ls_nodes_fields TYPE ts_nodes_fields, ls_nodes_tables TYPE ts_nodes_tables. DATA: lv_gid TYPE i, lv_index TYPE i, lv_num TYPE num1, lv_count TYPE i, lv_value TYPE string, lv_tname TYPE text2. lr_tfilter = gr_document->create_filter_name( name = 'tr' namespace = 'w' ). lr_titerator = gr_document->create_iterator_filtered( lr_tfilter ). lr_tnode = lr_titerator->get_next( ). WHILE lr_tnode IS NOT INITIAL. lv_gid = lr_tnode->get_gid( ). * me->check_fields( lv_gid ). lr_ffilter = lr_tnode->create_filter_name( name = '#text' ). lr_fiterator = lr_tnode->create_iterator_filtered( lr_ffilter ). lr_fnode = lr_fiterator->get_next( ). WHILE lr_fnode IS NOT INITIAL. CLEAR lv_count. lv_num = 1. ls_nodes_fields-index = sy-index. ls_nodes_fields-gid = lv_gid. lv_value = lr_fnode->get_value( ). DO 10 TIMES. CONCATENATE '#' lv_num INTO lv_tname. FIND lv_tname IN lv_value MATCH COUNT lv_count. IF lv_count > 0. ls_nodes_fields-table = lv_num. APPEND ls_nodes_fields TO gt_nodes_fields. EXIT. ENDIF. lv_num = lv_num + 1. ENDDO. IF lv_count > 0. READ TABLE gt_nodes_tables WITH KEY table = lv_num gid = lv_gid TRANSPORTING NO FIELDS. IF sy-subrc IS NOT INITIAL. ls_nodes_tables-table = lv_num. ls_nodes_tables-gid = lv_gid. APPEND ls_nodes_tables TO gt_nodes_tables. ENDIF. ENDIF. lr_fnode = lr_fiterator->get_next( ). ENDWHILE. FREE: lr_ffilter, lr_fiterator, lr_fnode. lr_tnode = lr_titerator->get_next( ). ENDWHILE. ENDMETHOD. "check_fields METHOD check_report. me->check_tables( ). me->check_fields( ). ENDMETHOD. "check_tables ENDCLASS. "lcl_docx IMPLEMENTATION PARAMETERS p_file TYPE text250 DEFAULT 'c:\temp\1.docx'. DATA: l_data_xml TYPE xstring. DATA: l_filename TYPE string. START-OF-SELECTION. l_filename = p_file. TRY. l_data_xml = cl_openxml_helper=>load_local_file( l_filename ). CATCH cx_openxml_not_found. ENDTRY. DATA: gr_docx TYPE REF TO lcl_docx. CREATE OBJECT gr_docx EXPORTING string = l_data_xml. gr_docx->add_field( iv_field = 'DATE1' iv_value = '01.01.2013'). gr_docx->add_field( iv_field = 'FIO' iv_value = 'Иванов Иван Иванович'). DO 1000 TIMES. gr_docx->new_line( ). gr_docx->add_field( iv_table = '1' iv_field = 'DATA' iv_value = 'text1 table1'). gr_docx->add_field( iv_table = '1' iv_field = 'NUM' iv_value = sy-index ). gr_docx->new_line( ). gr_docx->add_field( iv_table = '1' iv_field = 'DATA' iv_value = 'text2 table1'). gr_docx->add_field( iv_table = '1' iv_field = 'NUM' iv_value = '1.2.'). gr_docx->new_line( ). gr_docx->add_field( iv_table = '2' iv_field = 'DATA' iv_value = 'text1 table2'). gr_docx->add_field( iv_table = '2' iv_field = 'NUM' iv_value = '2.1.'). gr_docx->new_line( ). gr_docx->add_field( iv_table = '2' iv_field = 'DATA' iv_value = 'text2 table2'). gr_docx->add_field( iv_table = '2' iv_field = 'NUM' iv_value = '2.2.'). gr_docx->new_line( ). gr_docx->add_field( iv_table = '1' iv_field = 'DATA' iv_value = 'text3 table1'). gr_docx->add_field( iv_table = '1' iv_field = 'NUM' iv_value = '1.3.'). ENDDO. gr_docx->fill_data( ). l_data_xml = gr_docx->get_document( ). cl_openxml_helper=>store_local_file( im_file_name = 'c:\temp\3.docx' im_data = l_data_xml ). |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |