Closed AndreaBorgia-Abo closed 1 week ago
Thanks a lot! I will include the local classes lcl_rewrite_xml_via_sxml
and ltc_rewrite_xml_via_sxml
in ZDEMO_EXCEL_CHECKER
.
The below information is for me.
Current situation:
CALL METHOD ('ZCL_EXCEL_XML')=>rewrite_xml_via_sxml
EXPORTING iv_xml_string = lv_string
RECEIVING rv_string = lv_string.
To be:
lv_string = lcl_rewrite_xml_via_sxml=>rewrite_xml_via_sxml( lv_string ).
Code to include:
CLASS ltc_rewrite_xml_via_sxml DEFINITION DEFERRED.
CLASS lcl_rewrite_xml_via_sxml DEFINITION
FINAL
CREATE PRIVATE
FRIENDS ltc_rewrite_xml_via_sxml.
PUBLIC SECTION.
CLASS-METHODS execute
IMPORTING
iv_xml_string TYPE string
iv_trace TYPE abap_bool DEFAULT abap_false
RETURNING
VALUE(rv_string) TYPE string.
PRIVATE SECTION.
TYPES:
BEGIN OF ts_attribute,
name TYPE string,
namespace TYPE string,
prefix TYPE string,
END OF ts_attribute.
TYPES tt_attribute TYPE STANDARD TABLE OF ts_attribute WITH DEFAULT KEY.
TYPES:
BEGIN OF ts_element,
name TYPE string,
namespace TYPE string,
prefix TYPE string,
END OF ts_element.
TYPES:
BEGIN OF ts_nsbinding,
prefix TYPE string,
nsuri TYPE string,
END OF ts_nsbinding.
TYPES tt_nsbinding TYPE STANDARD TABLE OF ts_nsbinding WITH DEFAULT KEY.
TYPES:
BEGIN OF ts_complete_element,
element TYPE ts_element,
attributes TYPE tt_attribute,
nsbindings TYPE tt_nsbinding,
END OF ts_complete_element.
CLASS-DATA complete_parsed_elements TYPE TABLE OF ts_complete_element.
ENDCLASS.
CLASS lcl_rewrite_xml_via_sxml IMPLEMENTATION.
METHOD execute.
TYPES:
BEGIN OF ts_level,
number TYPE i,
nsbindings TYPE if_sxml_named=>nsbindings,
END OF ts_level.
TYPES:
BEGIN OF ts_attribute_sorting,
prefix TYPE string,
name TYPE string,
object TYPE REF TO if_sxml_attribute,
END OF ts_attribute_sorting.
DATA lv_current_level TYPE i.
DATA ls_level TYPE ts_level.
DATA lt_level TYPE STANDARD TABLE OF ts_level WITH DEFAULT KEY.
DATA lo_reader TYPE REF TO if_sxml_reader.
DATA lo_string_writer TYPE REF TO cl_sxml_string_writer.
DATA lo_writer TYPE REF TO if_sxml_writer.
DATA lo_node TYPE REF TO if_sxml_node.
DATA lo_close_element TYPE REF TO if_sxml_close_element.
DATA lo_open_element TYPE REF TO if_sxml_open_element.
DATA lt_nsbinding TYPE if_sxml_named=>nsbindings.
DATA lt_attribute TYPE if_sxml_attribute=>attributes.
DATA ls_complete_element TYPE ts_complete_element.
DATA lr_nsbinding TYPE REF TO if_sxml_named=>nsbinding.
DATA ls_nsbinding TYPE ts_nsbinding.
DATA lo_attribute TYPE REF TO if_sxml_attribute.
DATA ls_attribute TYPE ts_attribute.
DATA lt_attribute_sorting TYPE TABLE OF ts_attribute_sorting.
DATA ls_attribute_sorting TYPE ts_attribute_sorting.
DATA lt_new_nsbinding TYPE if_sxml_named=>nsbindings.
DATA lo_value_node TYPE REF TO if_sxml_value_node.
DATA lv_string TYPE string.
FIELD-SYMBOLS <ls_level> TYPE ts_level.
CLEAR complete_parsed_elements.
lv_current_level = 1.
ls_level-number = lv_current_level.
INSERT ls_level INTO TABLE lt_level ASSIGNING <ls_level>.
lo_reader = cl_sxml_string_reader=>create( input = cl_abap_codepage=>convert_to( iv_xml_string ) ).
lo_string_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 ).
lo_writer = lo_string_writer.
DO.
lo_node = lo_reader->read_next_node( ).
IF lo_node IS NOT BOUND.
" End of XML
EXIT.
ENDIF.
CASE lo_node->type.
WHEN lo_node->co_nt_attribute.
"should not happen in OO parsing (READ_NEXT_NODE)
RAISE EXCEPTION TYPE lcx_unexpected.
WHEN lo_node->co_nt_element_close.
DELETE lt_level INDEX lv_current_level.
lv_current_level = lv_current_level - 1.
READ TABLE lt_level INDEX lv_current_level ASSIGNING <ls_level>.
lo_close_element = lo_writer->new_close_element( ).
lo_writer->write_node( lo_close_element ).
WHEN lo_node->co_nt_element_open.
lo_open_element ?= lo_node.
lt_nsbinding = lo_reader->get_nsbindings( ).
lt_attribute = lo_open_element->get_attributes( ).
IF iv_trace = abap_true.
CLEAR ls_complete_element.
ls_complete_element-element-name = lo_open_element->qname-name.
ls_complete_element-element-namespace = lo_open_element->qname-namespace.
ls_complete_element-element-prefix = lo_open_element->prefix.
LOOP AT lt_nsbinding REFERENCE INTO lr_nsbinding.
ls_nsbinding-prefix = lr_nsbinding->prefix.
ls_nsbinding-nsuri = lr_nsbinding->nsuri.
INSERT ls_nsbinding INTO TABLE ls_complete_element-nsbindings.
ENDLOOP.
LOOP AT lt_attribute INTO lo_attribute.
ls_attribute-name = lo_attribute->qname-name.
ls_attribute-namespace = lo_attribute->qname-namespace.
ls_attribute-prefix = lo_attribute->prefix.
INSERT ls_attribute INTO TABLE ls_complete_element-attributes.
ENDLOOP.
INSERT ls_complete_element INTO TABLE complete_parsed_elements.
ENDIF.
IF lo_open_element->prefix IS INITIAL.
lo_open_element = lo_writer->new_open_element( name = lo_open_element->qname-name ).
ELSE.
lo_open_element = lo_writer->new_open_element( name = lo_open_element->qname-name
nsuri = lo_open_element->qname-namespace
prefix = lo_open_element->prefix ).
ENDIF.
CLEAR lt_attribute_sorting.
LOOP AT lt_attribute INTO lo_attribute.
ls_attribute_sorting-prefix = lo_attribute->prefix.
ls_attribute_sorting-name = lo_attribute->qname-name.
ls_attribute_sorting-object = lo_attribute.
INSERT ls_attribute_sorting INTO TABLE lt_attribute_sorting.
ENDLOOP.
SORT lt_attribute_sorting BY prefix name.
lo_open_element->set_attributes( lt_attribute ).
CLEAR lt_new_nsbinding.
LOOP AT lt_nsbinding REFERENCE INTO lr_nsbinding.
READ TABLE <ls_level>-nsbindings TRANSPORTING NO FIELDS WITH KEY prefix = lr_nsbinding->prefix
nsuri = lr_nsbinding->nsuri.
IF sy-subrc <> 0.
" It's the first time the default namespace is used,
" or if it has been changed, then declare it.
" (the default namespace must be set via set_attribute before the element
" is written, while other namespaces must be written using
" write_namespace_declaration after the element is written)
IF lr_nsbinding->prefix IS INITIAL.
lo_open_element->set_attribute( name = 'xmlns'
value = lr_nsbinding->nsuri ).
ELSE.
INSERT lr_nsbinding->* INTO TABLE lt_new_nsbinding.
ENDIF.
ENDIF.
ENDLOOP.
lv_current_level = lv_current_level + 1.
ls_level-number = lv_current_level.
ls_level-nsbindings = lt_nsbinding.
INSERT ls_level INTO TABLE lt_level ASSIGNING <ls_level>.
lo_writer->write_node( node = lo_open_element ).
SORT lt_new_nsbinding BY prefix.
LOOP AT lt_new_nsbinding REFERENCE INTO lr_nsbinding
WHERE prefix IS NOT INITIAL.
lo_writer->write_namespace_declaration( nsuri = lr_nsbinding->nsuri
prefix = lr_nsbinding->prefix ).
ENDLOOP.
WHEN lo_node->co_nt_final.
"should not happen in OO parsing
RAISE EXCEPTION TYPE lcx_unexpected.
WHEN lo_node->co_nt_initial.
"should not happen in OO parsing
RAISE EXCEPTION TYPE lcx_unexpected.
WHEN lo_node->co_nt_value.
lo_value_node ?= lo_node.
lv_string = lo_value_node->get_value( ).
lo_value_node = lo_writer->new_value( ).
lo_value_node->set_value( lv_string ).
lo_writer->write_node( lo_value_node ).
WHEN OTHERS.
"should not happen whatever it's OO or token parsing
RAISE EXCEPTION TYPE lcx_unexpected.
ENDCASE.
ENDDO.
rv_string = cl_abap_codepage=>convert_from( lo_string_writer->get_output( ) ).
ENDMETHOD.
ENDCLASS.
CLASS ltc_rewrite_xml_via_sxml DEFINITION
FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS default_namespace FOR TESTING RAISING cx_static_check.
METHODS default_namespace_removed FOR TESTING RAISING cx_static_check.
METHODS namespace FOR TESTING RAISING cx_static_check.
METHODS namespace_2 FOR TESTING RAISING cx_static_check.
METHODS namespace_3 FOR TESTING RAISING cx_static_check.
DATA parsed_element_index TYPE i.
DATA string TYPE string.
METHODS get_expected_attribute
IMPORTING
iv_name TYPE string
iv_namespace TYPE string DEFAULT ``
iv_prefix TYPE string DEFAULT ``
RETURNING
VALUE(rs_result) TYPE lcl_rewrite_xml_via_sxml=>ts_attribute.
METHODS get_expected_element
IMPORTING
iv_name TYPE string
iv_namespace TYPE string DEFAULT ``
iv_prefix TYPE string DEFAULT ``
RETURNING
VALUE(rs_result) TYPE lcl_rewrite_xml_via_sxml=>ts_element.
METHODS get_expected_nsbinding
IMPORTING
iv_prefix TYPE string DEFAULT ``
iv_nsuri TYPE string DEFAULT ``
RETURNING
VALUE(rs_result) TYPE lcl_rewrite_xml_via_sxml=>ts_nsbinding.
METHODS get_parsed_element
RETURNING
VALUE(rs_result) TYPE lcl_rewrite_xml_via_sxml=>ts_element.
METHODS get_parsed_element_attribute
IMPORTING
iv_index TYPE i
RETURNING
VALUE(rs_result) TYPE lcl_rewrite_xml_via_sxml=>ts_attribute.
METHODS get_parsed_element_nsbinding
IMPORTING
iv_index TYPE i
RETURNING
VALUE(rs_result) TYPE lcl_rewrite_xml_via_sxml=>ts_nsbinding.
METHODS rewrite_xml_via_sxml
IMPORTING
iv_xml_string TYPE string
RETURNING
VALUE(rv_string) TYPE string.
METHODS set_current_parsed_element
IMPORTING
iv_index TYPE i.
ENDCLASS.
CLASS ltc_rewrite_xml_via_sxml IMPLEMENTATION.
METHOD default_namespace.
string = rewrite_xml_via_sxml(
`<A xmlns="dnsuri" xmlns:nsprefix="nsuri" nsprefix:attr="1" attr="2"><B attr="3"/></A>` ).
cl_abap_unit_assert=>assert_equals(
act = string
exp = `<A nsprefix:attr="1" attr="2" xmlns="dnsuri" xmlns:nsprefix="nsuri"><B attr="3"/></A>` ).
set_current_parsed_element( iv_index = 1 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'A'
iv_namespace = 'dnsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 1 )
exp = get_expected_nsbinding( iv_prefix = 'nsprefix'
iv_nsuri = 'nsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 2 )
exp = get_expected_nsbinding( iv_nsuri = 'dnsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_attribute( iv_index = 1 )
exp = get_expected_attribute( iv_name = 'attr'
iv_namespace = 'nsuri'
iv_prefix = 'nsprefix' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_attribute( iv_index = 2 )
exp = get_expected_attribute( iv_name = 'attr' ) ).
set_current_parsed_element( iv_index = 2 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'B'
iv_namespace = 'dnsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 1 )
exp = get_expected_nsbinding( iv_prefix = 'nsprefix'
iv_nsuri = 'nsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 2 )
exp = get_expected_nsbinding( iv_nsuri = 'dnsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_attribute( iv_index = 1 )
exp = get_expected_attribute( iv_name = 'attr' ) ).
ENDMETHOD.
METHOD default_namespace_removed.
string = rewrite_xml_via_sxml( `<A><B xmlns="dnsuri"><C xmlns=""><D/></C></B></A>` ).
cl_abap_unit_assert=>assert_equals( act = string
exp = `<A><B xmlns="dnsuri"><C xmlns=""><D/></C></B></A>` ).
set_current_parsed_element( iv_index = 1 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'A' ) ).
set_current_parsed_element( iv_index = 2 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'B'
iv_namespace = 'dnsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 1 )
exp = get_expected_nsbinding( iv_nsuri = 'dnsuri' ) ).
set_current_parsed_element( iv_index = 3 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'C' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 1 )
exp = get_expected_nsbinding( iv_nsuri = '' ) ).
set_current_parsed_element( iv_index = 4 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'D' ) ).
ENDMETHOD.
METHOD get_expected_attribute.
rs_result-name = iv_name.
rs_result-namespace = iv_namespace.
rs_result-prefix = iv_prefix.
ENDMETHOD.
METHOD get_expected_element.
rs_result-name = iv_name.
rs_result-namespace = iv_namespace.
rs_result-prefix = iv_prefix.
ENDMETHOD.
METHOD get_expected_nsbinding.
rs_result-prefix = iv_prefix.
rs_result-nsuri = iv_nsuri.
ENDMETHOD.
METHOD get_parsed_element.
DATA lr_complete_parsed_element TYPE REF TO lcl_rewrite_xml_via_sxml=>ts_complete_element.
READ TABLE lcl_rewrite_xml_via_sxml=>complete_parsed_elements REFERENCE INTO lr_complete_parsed_element INDEX parsed_element_index.
IF sy-subrc = 0.
rs_result = lr_complete_parsed_element->element.
ENDIF.
ENDMETHOD.
METHOD get_parsed_element_attribute.
DATA lr_complete_parsed_element TYPE REF TO lcl_rewrite_xml_via_sxml=>ts_complete_element.
READ TABLE lcl_rewrite_xml_via_sxml=>complete_parsed_elements REFERENCE INTO lr_complete_parsed_element INDEX parsed_element_index.
IF sy-subrc = 0.
READ TABLE lr_complete_parsed_element->attributes INTO rs_result INDEX iv_index.
ENDIF.
ENDMETHOD.
METHOD get_parsed_element_nsbinding.
DATA lr_complete_parsed_element TYPE REF TO lcl_rewrite_xml_via_sxml=>ts_complete_element.
READ TABLE lcl_rewrite_xml_via_sxml=>complete_parsed_elements REFERENCE INTO lr_complete_parsed_element INDEX parsed_element_index.
IF sy-subrc = 0.
READ TABLE lr_complete_parsed_element->nsbindings INTO rs_result INDEX iv_index.
ENDIF.
ENDMETHOD.
METHOD namespace.
string = rewrite_xml_via_sxml(
`<nsprefix:A xmlns="dnsuri" xmlns:nsprefix="nsuri" nsprefix:attr="1" attr="2"><B attr="3"/></nsprefix:A>` ).
cl_abap_unit_assert=>assert_equals(
act = string
exp = `<nsprefix:A nsprefix:attr="1" attr="2" xmlns="dnsuri" xmlns:nsprefix="nsuri"><B attr="3"/></nsprefix:A>` ).
cl_abap_unit_assert=>assert_equals( act = rewrite_xml_via_sxml( `<A xmlns=""/>` )
exp = `<A xmlns=""/>` ).
cl_abap_unit_assert=>assert_equals( act = rewrite_xml_via_sxml( `<A xmlns=""><B/></A>` )
exp = `<A xmlns=""><B/></A>` ).
cl_abap_unit_assert=>assert_equals( act = rewrite_xml_via_sxml( `<A><B xmlns=""/></A>` )
exp = `<A><B xmlns=""/></A>` ).
ENDMETHOD.
METHOD namespace_2.
string = rewrite_xml_via_sxml( `<A xmlns="dnsuri" xmlns:nsprefix="nsuri"><B/><nsprefix:C/></A>` ).
cl_abap_unit_assert=>assert_equals( act = string
exp = `<A xmlns="dnsuri" xmlns:nsprefix="nsuri"><B/><nsprefix:C/></A>` ).
set_current_parsed_element( iv_index = 1 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'A'
iv_namespace = 'dnsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 1 )
exp = get_expected_nsbinding( iv_prefix = 'nsprefix'
iv_nsuri = 'nsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 2 )
exp = get_expected_nsbinding( iv_nsuri = 'dnsuri' ) ).
set_current_parsed_element( iv_index = 2 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'B'
iv_namespace = 'dnsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 1 )
exp = get_expected_nsbinding( iv_prefix = 'nsprefix'
iv_nsuri = 'nsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 2 )
exp = get_expected_nsbinding( iv_nsuri = 'dnsuri' ) ).
set_current_parsed_element( iv_index = 3 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'C'
iv_namespace = 'nsuri'
iv_prefix = 'nsprefix' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 1 )
exp = get_expected_nsbinding( iv_prefix = 'nsprefix'
iv_nsuri = 'nsuri' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 2 )
exp = get_expected_nsbinding( iv_nsuri = 'dnsuri' ) ).
ENDMETHOD.
METHOD namespace_3.
string = rewrite_xml_via_sxml( `<a:A xmlns:a="nsuri_a"><b:B xmlns:b="nsuri_b"/></a:A>` ).
cl_abap_unit_assert=>assert_equals( act = string
exp = `<a:A xmlns:a="nsuri_a"><b:B xmlns:b="nsuri_b"/></a:A>` ).
set_current_parsed_element( iv_index = 1 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'A'
iv_namespace = 'nsuri_a'
iv_prefix = 'a' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 1 )
exp = get_expected_nsbinding( iv_prefix = 'a'
iv_nsuri = 'nsuri_a' ) ).
set_current_parsed_element( iv_index = 2 ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element( )
exp = get_expected_element( iv_name = 'B'
iv_namespace = 'nsuri_b'
iv_prefix = 'b' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 1 )
exp = get_expected_nsbinding( iv_prefix = 'b'
iv_nsuri = 'nsuri_b' ) ).
cl_abap_unit_assert=>assert_equals( act = get_parsed_element_nsbinding( iv_index = 2 )
exp = get_expected_nsbinding( iv_prefix = 'a'
iv_nsuri = 'nsuri_a' ) ).
ENDMETHOD.
METHOD rewrite_xml_via_sxml.
rv_string = lcl_rewrite_xml_via_sxml=>execute( iv_xml_string = iv_xml_string
iv_trace = abap_true ).
ENDMETHOD.
METHOD set_current_parsed_element.
parsed_element_index = iv_index.
ENDMETHOD.
ENDCLASS.
Original sources:
lcl_rewrite_xml_via_sxml
ltc_rewrite_xml_via_sxml
to reproduce: start checker, unmark "exact XML" and continue.
Check stops with error message "Class ZCL_EXCEL_XML is missing, version of abap2xlsx is too old" in line 750
Most likely related to https://github.com/abap2xlsx/abap2xlsx/pull/1188 and https://github.com/sandraros/ixml-cloud