From time to time there are questions how to transform XML data to JSON data. If you search the Web you find quite a bunch of such converters, e.g.,
In those you paste some XML data and get them back as JSON data. The results of these converters are similar. Especially they follow the same conventions regarding which parts of the XML data are converted to JSON objects and which are converted to JSON arrays.
But is this possible in ABAP too? Are there general classes or function modules for that? I don't know and I didn't look. Instead I accepted the challenge to write a prototype myself.
Creating such a converter with the help of ABAP might be done in several ways:
As an old ABAPer I use the parsing/rendering way by employing the token based parsing and rendering offered by the methods of the sXML library. Here is my code:
TYPES: BEGIN OF node,
node_type TYPE if_sxml_node=>node_type,
name TYPE string,
value TYPE string,
array TYPE c LENGTH 1,
END OF node.
DATA nodes TYPE TABLE OF node WITH EMPTY KEY.
DATA(xml_string) = `<root />`.
DO.
cl_demo_text=>edit_string(
EXPORTING
title = 'XML-Data'
CHANGING
text_string = xml_string
EXCEPTIONS
canceled = 4 ).
IF sy-subrc = 4.
EXIT.
ENDIF.
DATA(xml) = cl_abap_codepage=>convert_to(
replace( val = xml_string sub = |\n| with = `` occ = 0 ) ).
DATA(out) = cl_demo_output=>new(
)->begin_section( `XML-Data`
)->write_xml( xml ).
"Parsing XML into an internal table
DATA(reader) = cl_sxml_string_reader=>create( xml ).
CLEAR nodes.
TRY.
DO.
reader->next_node( ).
IF reader->node_type = if_sxml_node=>co_nt_final.
EXIT.
ENDIF.
APPEND VALUE #(
node_type = reader->node_type
name = reader->prefix &&
COND string(
WHEN reader->prefix IS NOT INITIAL
THEN `:` ) && reader->name
value = reader->value ) TO nodes.
IF reader->node_type = if_sxml_node=>co_nt_element_open.
DO.
reader->next_attribute( ).
IF reader->node_type <> if_sxml_node=>co_nt_attribute.
EXIT.
ENDIF.
APPEND VALUE #(
node_type = if_sxml_node=>co_nt_initial
name = reader->prefix &&
COND string(
WHEN reader->prefix IS NOT INITIAL
THEN `:` ) && reader->name
value = reader->value ) TO nodes.
ENDDO.
ENDIF.
ENDDO.
CATCH cx_sxml_parse_error INTO DATA(parse_error).
out->write_text( parse_error->get_text( ) ).
ENDTRY.
"Determine the array limits in the internal table
LOOP AT nodes ASSIGNING FIELD-SYMBOL(<node_open>)
WHERE
node_type = if_sxml_node=>co_nt_element_open
AND array IS INITIAL.
DATA(idx_open) = sy-tabix.
LOOP AT nodes ASSIGNING FIELD-SYMBOL(<node_close>)
FROM idx_open + 1
WHERE
node_type = if_sxml_node=>co_nt_element_close
AND name = <node_open>-name.
DATA(idx_close) = sy-tabix.
IF idx_close < lines( nodes ).
ASSIGN nodes[ idx_close + 1 ] TO FIELD-SYMBOL(<node>).
IF <node>-node_type = if_sxml_node=>co_nt_element_open AND
<node>-name = <node_open>-name.
<node_open>-array = 'O'.
<node>-array = '_'.
ELSEIF
( <node>-node_type = if_sxml_node=>co_nt_element_open
AND <node>-name <> <node_open>-name )
OR <node>-node_type = if_sxml_node=>co_nt_element_close.
<node_close>-array = COND #(
WHEN <node_open>-array = 'O' THEN 'C' ).
EXIT.
ENDIF.
ENDIF.
ENDLOOP.
ENDLOOP.
"Render the internal table to JSON-XML
DATA(writer) = CAST if_sxml_writer(
cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ) ).
"create( type = if_sxml=>co_xt_xml10 ) ).
TRY.
writer->open_element( name = 'object' ).
LOOP AT nodes ASSIGNING <node>.
CASE <node>-node_type.
WHEN if_sxml_node=>co_nt_element_open.
IF <node>-array IS INITIAL.
writer->open_element( name = 'object' ).
writer->write_attribute( name = 'name'
value = <node>-name ).
ELSEIF <node>-array = 'O'.
writer->open_element( name = 'array' ).
writer->write_attribute( name = 'name'
value = <node>-name ).
writer->open_element( name = 'object' ).
ELSEIF <node>-array = '_'.
writer->open_element( name = 'object' ).
ENDIF.
WHEN if_sxml_node=>co_nt_element_close.
IF <node>-array <> 'C'.
writer->close_element( ).
ELSE.
writer->close_element( ).
writer->close_element( ).
ENDIF.
WHEN if_sxml_node=>co_nt_initial.
writer->open_element( name = 'str' ).
writer->write_attribute( name = 'name'
value = `a_` && <node>-name ).
writer->write_value( <node>-value ).
writer->close_element( ).
WHEN if_sxml_node=>co_nt_value.
writer->open_element( name = 'str' ).
writer->write_attribute( name = 'name'
value = `e_` && <node>-name ).
writer->write_value( <node>-value ).
writer->close_element( ).
WHEN OTHERS.
out->display( 'A node type is not yet supported' ).
RETURN.
ENDCASE.
ENDLOOP.
writer->close_element( ).
DATA(json) =
CAST cl_sxml_string_writer( writer )->get_output( ).
out->next_section( 'JSON-Data' ).
IF writer->if_sxml~type = if_sxml=>co_xt_json.
out->write_json( json ).
ELSEIF writer->if_sxml~type = if_sxml=>co_xt_xml10.
out->write_xml( json ).
ENDIF.
CATCH cx_sxml_error INTO DATA(exc).
out->write( exc->get_text( ) ).
ENDTRY.
out->display( ).
ENDDO.
This example allows you to enter some valid XML into a text edit control and tries to convert it to JSON.
And that's that.
If you enter XML data, e.g. as follows:
<order number="4711" xmlns:demo="http://www.sap.com/abapdemos">
<demo:head>
<demo:status>confirmed</demo:status>
<demo:date format="mm‑dd‑yyyy">07‑19‑2012</demo:date>
</demo:head>
<demo:body>
<demo:item units="2" price="17.00">Part No. 0110</demo:item>
<demo:item units="1" price="10.50">Part No. 1609</demo:item>
<demo:item units="5" price="12.30">Part No. 1710</demo:item>
</demo:body>
</order>
You receive the following JSON data.
{
"order":
{
"a_number":"4711",
"demo:head":
{
"demo:status":
{
"e_demo:status":"confirmed"
},
"demo:date":
{
"a_format":"mm‑dd‑yyyy",
"e_demo:date":"07‑19‑2012"
}
},
"demo:body":
{
"demo:item":
[
{
"a_units":"2",
"a_price":"17.00",
"e_demo:item":"Part No. 0110"
},
{
"a_units":"1",
"a_price":"10.50",
"e_demo:item":"Part No. 1609"
},
{
"a_units":"5",
"a_price":"12.30",
"e_demo:item":"Part No. 1710"
}
]
}
}
}
The result is at least similar to those of the above mentioned online converters, yay!
If you create an XML writer instead of the JSON writer in the above code with create( type = if_sxml=>co_xt_xml10 ), you receive and display the JSON-XML.
The program is far from being bullet-proof. Just an example, tested with some harmless XML data. I restricted the conversion to textual data (no numbers in JSON, no handling of raws) and other things might be missing to. Be invited to find errors and gaps and propose solutions. Maybe there is even an official tool available?
Cheers!
Horst
PS:
Be aware, that there is not one standard way of converting arbitrary XML data to JSON data. Or is there?
The conversions shown here are based on some conventions. In real life examples the desired results might look different and depend on the semantical data structure based on XSD, XML schema or whatsoever. I would expect that in most (business) use cases transformations from XML to JSON are rather specific than general.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
5 | |
4 | |
4 | |
4 | |
3 | |
3 | |
2 | |
2 | |
2 | |
2 |