From 37671d6ad7945ef92483c9052634467f333ea784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BCdiger=20Plantiko?= Date: Fri, 2 May 2014 22:26:13 +0200 Subject: [PATCH] Fixed a bug in shared string table reading There was a book in reading strings from the SST, caused by not catching the "node value" event in the main loop. Shared strings could point wrongly to the first table element (which usually contains the empty string). --- ZA2X/CLAS/ZCL_EXCEL_READER_HUGE_FILE.slnk | 433 ++++++++++++---------- 1 file changed, 245 insertions(+), 188 deletions(-) diff --git a/ZA2X/CLAS/ZCL_EXCEL_READER_HUGE_FILE.slnk b/ZA2X/CLAS/ZCL_EXCEL_READER_HUGE_FILE.slnk index b905b3e..dd1dab6 100644 --- a/ZA2X/CLAS/ZCL_EXCEL_READER_HUGE_FILE.slnk +++ b/ZA2X/CLAS/ZCL_EXCEL_READER_HUGE_FILE.slnk @@ -1,21 +1,35 @@ - - + - - *"* use this source file for the definition and implementation of *"* local helper classes, interface definitions and type @@ -26,11 +40,11 @@ class lcx_not_found implementation. method constructor. super->constructor( textid = textid previous = previous ). me->error = error. - endmethod. + endmethod. "constructor method if_message~get_text. result = error. - endmethod. -endclass. + endmethod. "if_message~get_text +endclass. "lcx_not_found IMPLEMENTATION *"* use this source file for any type of declarations (class *"* definitions, interfaces or type declarations) you need for *"* components in the private section @@ -48,123 +62,150 @@ endclass. *"* use this source file for any macro definitions you need *"* in the implementation part of the class *"* use this source file for your ABAP unit test classes -CLASS lcl_test DEFINITION DEFERRED. -CLASS zcl_excel_reader_huge_file DEFINITION LOCAL FRIENDS lcl_test. +class lcl_test definition deferred. +class zcl_excel_reader_huge_file definition local friends lcl_test. * -CLASS lcl_test DEFINITION FOR TESTING " #AU Risk_Level Harmless - INHERITING FROM cl_aunit_assert. " #AU Duration Short +class lcl_test definition for testing " #AU Risk_Level Harmless + inheriting from cl_aunit_assert. " #AU Duration Short - PRIVATE SECTION. - DATA: - out TYPE REF TO zcl_excel_reader_huge_file, " object under test - excel TYPE REF TO zcl_excel, - worksheet TYPE REF TO zcl_excel_worksheet. - METHODS: + private section. + data: + out type ref to zcl_excel_reader_huge_file, " object under test + excel type ref to zcl_excel, + worksheet type ref to zcl_excel_worksheet. + methods: setup, - test_number FOR TESTING, - test_shared_string FOR TESTING, - test_shared_string_missing FOR TESTING, - test_inline_string FOR TESTING, - test_boolean FOR TESTING, - test_style FOR TESTING, - test_style_missing FOR TESTING, - test_formula FOR TESTING, - test_read_shared_strings FOR TESTING, - test_skip_to_inexistent FOR TESTING, - get_reader IMPORTING iv_xml TYPE string RETURNING VALUE(eo_reader) TYPE REF TO if_sxml_reader, - assert_value_equals IMPORTING iv_row TYPE i DEFAULT 1 iv_col TYPE i DEFAULT 1 iv_value TYPE string, - assert_formula_equals IMPORTING iv_row TYPE i DEFAULT 1 iv_col TYPE i DEFAULT 1 iv_formula TYPE string, - assert_style_equals IMPORTING iv_row TYPE i DEFAULT 1 iv_col TYPE i DEFAULT 1 iv_style TYPE zexcel_cell_style, - assert_datatype_equals IMPORTING iv_row TYPE i DEFAULT 1 iv_col TYPE i DEFAULT 1 iv_datatype TYPE string. + test_number for testing, + test_shared_string for testing, + test_shared_string_missing for testing, + test_inline_string for testing, + test_empty_cells for testing, + test_boolean for testing, + test_style for testing, + test_style_missing for testing, + test_formula for testing, + test_read_shared_strings for testing, + test_skip_to_inexistent for testing, + get_reader importing iv_xml type string returning value(eo_reader) type ref to if_sxml_reader, + assert_value_equals importing iv_row type i default 1 iv_col type i default 1 iv_value type string, + assert_formula_equals importing iv_row type i default 1 iv_col type i default 1 iv_formula type string, + assert_style_equals importing iv_row type i default 1 iv_col type i default 1 iv_style type ZEXCEL_CELL_STYLE, + assert_datatype_equals importing iv_row type i default 1 iv_col type i default 1 iv_datatype type string. -ENDCLASS. "lcl_test DEFINITION +endclass. "lcl_test DEFINITION * -CLASS lcl_test IMPLEMENTATION. +class lcl_test implementation. * - METHOD test_number. - DATA lo_reader TYPE REF TO if_sxml_reader. + method test_number. + data lo_reader type ref to if_sxml_reader. lo_reader = get_reader( `<c r="A1" t="n"><v>17</v></c>` ). out->read_worksheet_data( io_reader = lo_reader io_worksheet = worksheet ). assert_value_equals( `17` ). assert_datatype_equals( `n` ). - ENDMETHOD. "test_shared_string + endmethod. "test_shared_string * - METHOD test_shared_string. - DATA lo_reader TYPE REF TO if_sxml_reader. - APPEND `Test` TO out->shared_strings. + method test_shared_string. + data lo_reader type ref to if_sxml_reader. + append `Test1` to out->shared_strings. + append `Test2` to out->shared_strings. lo_reader = get_reader( - `<c r="A1" t="s"><v>0</v></c>` + `<c r="A1" t="s"><v>1</v></c>` ). out->read_worksheet_data( io_reader = lo_reader io_worksheet = worksheet ). - assert_value_equals( `Test` ). + assert_value_equals( `Test2` ). assert_datatype_equals( `s` ). - ENDMETHOD. "test_shared_string + endmethod. "test_shared_string * - METHOD test_shared_string_missing. + method test_shared_string_missing. - DATA: lo_reader TYPE REF TO if_sxml_reader, - lo_ex TYPE REF TO lcx_not_found, - lv_text TYPE string. + data: lo_reader type ref to if_sxml_reader, + lo_ex type ref to lcx_not_found, + lv_text type string. + append `Test` to out->shared_strings. lo_reader = get_reader( - `<c r="A1" t="s"><v>0</v></c>` + `<c r="A1" t="s"><v>1</v></c>` ). - TRY. + try. out->read_worksheet_data( io_reader = lo_reader io_worksheet = worksheet ). fail(`Index to non-existent shared string should give an error`). - CATCH lcx_not_found INTO lo_ex. + catch lcx_not_found into lo_ex. lv_text = lo_ex->get_text( ). " >>> May inspect the message in the debugger - ENDTRY. + endtry. - ENDMETHOD. + endmethod. * - METHOD test_inline_string. - DATA lo_reader TYPE REF TO if_sxml_reader. + method test_inline_string. + data lo_reader type ref to if_sxml_reader. lo_reader = get_reader( `<c r="A1" t="inlineStr"><is><t>Alpha</t></is></c>` ). out->read_worksheet_data( io_reader = lo_reader io_worksheet = worksheet ). assert_value_equals( `Alpha` ). assert_datatype_equals( `inlineStr` ). - ENDMETHOD. "test_inline_string + endmethod. "test_inline_string * - METHOD test_boolean. - DATA lo_reader TYPE REF TO if_sxml_reader. + method test_boolean. + data lo_reader type ref to if_sxml_reader. lo_reader = get_reader( `<c r="A1" t="b"><v>1</v></c>` ). out->read_worksheet_data( io_reader = lo_reader io_worksheet = worksheet ). assert_value_equals( `1` ). assert_datatype_equals( `b` ). - ENDMETHOD. "test_boolean + endmethod. "test_boolean * - METHOD test_formula. - DATA lo_reader TYPE REF TO if_sxml_reader. + method test_formula. + data lo_reader type ref to if_sxml_reader. lo_reader = get_reader( `<c r="A1" t="n"><f>A2*A2</f></c>` ). out->read_worksheet_data( io_reader = lo_reader io_worksheet = worksheet ). assert_formula_equals( `A2*A2` ). assert_datatype_equals( `n` ). - ENDMETHOD. "test_formula + endmethod. "test_formula * - METHOD test_style. - DATA: - lo_reader TYPE REF TO if_sxml_reader, - lo_style TYPE REF TO zcl_excel_style, - lv_guid TYPE zexcel_cell_style. - CREATE OBJECT lo_style. - APPEND lo_style TO out->styles. - lv_guid = lo_style->get_guid( ). + method test_empty_cells. + +* There is no need to store an empty cell in the ABAP worksheet structure + + data: lo_reader type ref to if_sxml_reader, + lo_ex type ref to lcx_not_found, + lv_text type string. + append `` to out->shared_strings. + append `t` to out->shared_strings. + lo_reader = get_reader( + `<c r="A1" t="s"><v>0</v></c>` && + `<c r="A2" t="inlineStr"><is><t></t></is></c>` && + `<c r="A3" t="s"><v>1</v></c>` + ). + + out->read_worksheet_data( io_reader = lo_reader io_worksheet = worksheet ). + + assert_value_equals( iv_row = 1 iv_col = 1 iv_value = `` ). + assert_value_equals( iv_row = 2 iv_col = 1 iv_value = `` ). + assert_value_equals( iv_row = 3 iv_col = 1 iv_value = `t` ). + + endmethod. + +* + method test_style. + data: + lo_reader type ref to if_sxml_reader, + lo_style type ref to zcl_excel_style, + lv_guid type ZEXCEL_CELL_STYLE. + create object lo_style. + append lo_style to out->styles. + lv_guid = lo_style->get_guid( ). lo_reader = get_reader( `<c r="A1" s="0"><v>18</v></c>` @@ -173,150 +214,162 @@ CLASS lcl_test IMPLEMENTATION. assert_style_equals( lv_guid ). - ENDMETHOD. "test_style + endmethod. "test_style * - METHOD test_style_missing. + method test_style_missing. - DATA: - lo_reader TYPE REF TO if_sxml_reader, - lo_ex TYPE REF TO lcx_not_found, - lv_text TYPE string. + data: + lo_reader type ref to if_sxml_reader, + lo_ex type ref to lcx_not_found, + lv_text type string. lo_reader = get_reader( `<c r="A1" s="0"><v>18</v></c>` ). - TRY. + try. out->read_worksheet_data( io_reader = lo_reader io_worksheet = worksheet ). fail(`Reference to non-existent style should throw an lcx_not_found exception`). - CATCH lcx_not_found INTO lo_ex. + catch lcx_not_found into lo_ex. lv_text = lo_ex->get_text( ). " >>> May inspect the message in the debugger - ENDTRY. + endtry. - ENDMETHOD. "test_style + endmethod. "test_style * - METHOD test_read_shared_strings. - DATA: lo_reader TYPE REF TO if_sxml_reader, - lt_act TYPE stringtab, - lt_exp TYPE stringtab. + method test_read_shared_strings. + data: lo_reader type ref to if_sxml_reader, + lt_act type stringtab, + lt_exp type stringtab. lo_reader = cl_sxml_string_reader=>create( cl_abap_codepage=>convert_to( `<sst><si><t/></si><si><t>Alpha</t></si><si><t>Bravo</t></si></sst>` ) ). - APPEND : - `` TO lt_exp, - `Alpha` TO lt_exp, - `Bravo` TO lt_exp. + append : + `` to lt_exp, + `Alpha` to lt_exp, + `Bravo` to lt_exp. lt_act = out->read_shared_strings( lo_reader ). assert_equals( act = lt_act exp = lt_exp ). - ENDMETHOD. + endmethod. * - METHOD test_skip_to_inexistent. - DATA: lo_reader TYPE REF TO if_sxml_reader, - lo_ex TYPE REF TO lcx_not_found, - lv_text TYPE string. + method test_skip_to_inexistent. + data: lo_reader type ref to if_sxml_reader, + lo_ex type ref to lcx_not_found, + lv_text type string. lo_reader = cl_sxml_string_reader=>create( cl_abap_codepage=>convert_to( `<sst><si><t/></si><si><t>Alpha</t></si><si><t>Bravo</t></si></sst>` ) ). - TRY. + try. out->skip_to( iv_element_name = `nonExistingElement` io_reader = lo_reader ). fail(`Skipping to non-existing element must raise lcx_not_found exception`). - CATCH lcx_not_found INTO lo_ex. + catch lcx_not_found into lo_ex. lv_text = lo_ex->get_text( ). " May inspect exception text in debugger - ENDTRY. - ENDMETHOD. + endtry. + endmethod. * - METHOD get_reader. - DATA: lv_full TYPE string. - CONCATENATE `<root><sheetData><row>` iv_xml `</row></sheetData></root>` INTO lv_full. + method get_reader. + data: lv_full type string. + concatenate `<root><sheetData><row>` iv_xml `</row></sheetData></root>` into lv_full. eo_reader = cl_sxml_string_reader=>create( cl_abap_codepage=>convert_to( lv_full ) ). - ENDMETHOD. "get_reader + endmethod. "get_reader * - METHOD assert_value_equals. + method assert_value_equals. - FIELD-SYMBOLS: <ls_cell_data> TYPE zexcel_s_cell_data. + constants: lc_empty_string type string value is initial. - READ TABLE worksheet->sheet_content ASSIGNING <ls_cell_data> - WITH TABLE KEY cell_row = iv_row cell_column = iv_col. - assert_subrc( sy-subrc ). + field-symbols: <ls_cell_data> type zexcel_s_cell_data, + <lv_value> type string. - assert_equals( act = <ls_cell_data>-cell_value + read table worksheet->sheet_content assigning <ls_cell_data> + with table key cell_row = iv_row cell_column = iv_col. + if sy-subrc eq 0. + assign <ls_cell_data>-cell_value to <lv_value>. + else. + assign lc_empty_string to <lv_value>. + endif. + + assert_equals( act = <lv_value> exp = iv_value ). - ENDMETHOD. "assert_value_equals + endmethod. "assert_value_equals ** - METHOD assert_formula_equals. + method assert_formula_equals. - FIELD-SYMBOLS: <ls_cell_data> TYPE zexcel_s_cell_data. + field-symbols: <ls_cell_data> type zexcel_s_cell_data. - READ TABLE worksheet->sheet_content ASSIGNING <ls_cell_data> - WITH TABLE KEY cell_row = iv_row cell_column = iv_col. + read table worksheet->sheet_content assigning <ls_cell_data> + with table key cell_row = iv_row cell_column = iv_col. assert_subrc( sy-subrc ). assert_equals( act = <ls_cell_data>-cell_formula exp = iv_formula ). - ENDMETHOD. "assert_formula_equals + endmethod. "assert_formula_equals * - METHOD assert_style_equals. + method assert_style_equals. - FIELD-SYMBOLS: <ls_cell_data> TYPE zexcel_s_cell_data. + field-symbols: <ls_cell_data> type zexcel_s_cell_data. - READ TABLE worksheet->sheet_content ASSIGNING <ls_cell_data> - WITH TABLE KEY cell_row = iv_row cell_column = iv_col. + read table worksheet->sheet_content assigning <ls_cell_data> + with table key cell_row = iv_row cell_column = iv_col. assert_subrc( sy-subrc ). assert_equals( act = <ls_cell_data>-cell_style exp = iv_style ). - ENDMETHOD. + endmethod. * - METHOD assert_datatype_equals. + method assert_datatype_equals. - FIELD-SYMBOLS: <ls_cell_data> TYPE zexcel_s_cell_data. + field-symbols: <ls_cell_data> type zexcel_s_cell_data. - READ TABLE worksheet->sheet_content ASSIGNING <ls_cell_data> - WITH TABLE KEY cell_row = iv_row cell_column = iv_col. + read table worksheet->sheet_content assigning <ls_cell_data> + with table key cell_row = iv_row cell_column = iv_col. assert_subrc( sy-subrc ). assert_equals( act = <ls_cell_data>-data_type exp = iv_datatype ). - ENDMETHOD. "assert_datatype_equals - METHOD setup. - CREATE OBJECT out. - CREATE OBJECT excel. - CREATE OBJECT worksheet - EXPORTING + endmethod. "assert_datatype_equals + method setup. + create object out. + create object excel. + create object worksheet + exporting ip_excel = excel. - ENDMETHOD. "setup -ENDCLASS. "lcl_test IMPLEMENTATION + endmethod. "setup +endclass. "lcl_test IMPLEMENTATION - - - - - + + + + + - - - - + + + + method FILL_CELL_FROM_ATTRIBUTES. while io_reader->node_type ne c_end_of_stream. @@ -336,13 +389,11 @@ ENDCLASS. "lcl_test IMPLEMENTATION endcase. endwhile. - io_reader->current_node( ). - endmethod. - - - + + + method GET_CELL_COORD. zcl_excel_common=>convert_columnrow2column_a_row( @@ -355,10 +406,10 @@ endmethod. endmethod. - - - - + + + + method GET_SHARED_STRING. data: lv_tabix type i. lv_tabix = iv_index + 1. @@ -370,10 +421,10 @@ endmethod. endif. endmethod. - - - - + + + + method GET_STYLE. data: lv_tabix type i, @@ -396,10 +447,10 @@ endmethod. endmethod. - - - - + + + + method GET_SXML_READER. data: lv_xml type xstring. @@ -432,10 +483,13 @@ endmethod. endmethod. - - - + + + method PUT_CELL_TO_WORKSHEET. + check is_cell-value is not initial + or is_cell-formula is not initial + or is_cell-style is not initial. call method io_worksheet->set_cell exporting ip_column = is_cell-column @@ -446,9 +500,9 @@ endmethod. ip_style = is_cell-style. endmethod. - - - + + + method READ_SHARED_STRINGS. while io_reader->node_type ne c_end_of_stream. @@ -461,10 +515,10 @@ endmethod. endmethod. - - - - + + + + method READ_WORKSHEET_DATA. data: ls_cell type t_cell. @@ -480,20 +534,23 @@ endmethod. if io_reader->name eq `c`. ls_cell = fill_cell_from_attributes( io_reader ). endif. - when c_element_close. + when c_node_value. case io_reader->name. - when `c`. - put_cell_to_worksheet( is_cell = ls_cell io_worksheet = io_worksheet ). when `f`. ls_cell-formula = io_reader->value. when `v`. if ls_cell-datatype eq `s`. - ls_cell-value = get_shared_string( ls_cell-value ). + ls_cell-value = get_shared_string( io_reader->value ). else. ls_cell-value = io_reader->value. endif. - when `is`. + when `t` or `is`. ls_cell-value = io_reader->value. + endcase. + when c_element_close. + case io_reader->name. + when `c`. + put_cell_to_worksheet( is_cell = ls_cell io_worksheet = io_worksheet ). when `sheetData`. exit. endcase. @@ -502,10 +559,10 @@ endmethod. endmethod. - - - - + + + + method SKIP_TO. * Skip forward to given element