Convert database query result to json/yaml/xml with ABAP - abap

Is there a way to convert a database query result to json/yaml/xml with ABAP?

DATA: lt_flight TYPE STANDARD TABLE OF sflight,
lrf_descr TYPE REF TO cl_abap_typedescr,
lv_json TYPE string.
SELECT * FROM sflight INTO TABLE lt_flight.
* serialize table lt_flight into JSON, skipping initial fields and converting ABAP field names into camelCase
lv_json = /ui2/cl_json=>serialize( data = lt_flight compress = abap_true pretty_name = /ui2/cl_json=>pretty_mode-camel_case ).
WRITE / lv_json.
CLEAR lt_flight.
* deserialize JSON string json into internal table lt_flight doing camelCase to ABAP like field name mapping
/ui2/cl_json=>deserialize( EXPORTING json = lv_json pretty_name = /ui2/cl_json=>pretty_mode-camel_case CHANGING data = lt_flight ).
* serialize ABAP object into JSON string
lrf_descr = cl_abap_typedescr=>describe_by_data( lt_flight ).
lv_json = /ui2/cl_json=>serialize( lrf_descr ).
WRITE / lv_json.
Output
[{"mandt":"000","carrid":"AA","connid":0017,"fldate":20130515,"price":422.94,"currency":"USD","planetype":"747-400","seatsmax":385,
"seatsocc":375,"paymentsum":192683.30,"seatsmaxB":31,"seatsoccB":31,"seatsmaxF":21,"seatsoccF":19},{"mandt":"000","carrid":"AA",
"connid....
{"ABSOLUTE_NAME":"\\TYPE=%_T00004S00000000O0000012480","ADMIN_TAB":"\\TYPE=%_T00004S00000000O0000012480",
"ADMIN_TAB_LINE":"\\TYPE=%_T00004S00000000O0000012480","DECIMALS":0,"HAS_UNIQUE_KEY":false,"INITIAL_SIZE":0,
"KEY":[{"NAME":"MANDT"},{"NAME":"CARRID"},{"NAME":"CO....
for more information please read Serializer and Deserializer
UPDATE
Another example:
First, you should create the ABAP to JSON Writer with the CL_SXML_STRING_WRITER with Json as Type.
Then Call the transformation to convert the String to JSON formatted String .
The last Step is to retrieve the Output of the Writer in JSON.
DATA text TYPE string VALUE `Hello JSON, I’m ABAP!`.
DATA writer TYPE REF TO cl_sxml_string_writer.
DATA json TYPE xstring.
“ABAP to JSON
writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).
CALL TRANSFORMATION id SOURCE text = text
RESULT XML writer.
json = writer->get_output( ).

Related

PDI: How to change unspecified fields meta type?

I'm handling random tables from a database, I have a field with table's schema, and another with table's name, that way I'm able to do a table input like the following inside a child transformation:
SELECT * FROM ${SCHEMA}.${TABLENAME};
After getting the table values as columns, I want to dynamically generate an SQL with dynamic WHERE clauses, with something like this within a User Defined Java class:
Object[] in = getRow();
String sql = String.format("SELECT %s FROM %s.%s WHERE ",
getParameter("KEYS"),
getParameter("SCHEMA"),
getParameter("TABLE"));
Object[] out = createOutputRow(in, data.outputRowMeta.size());
ArrayList<String> fieldNames = new ArrayList<String>(Arrays.asList(data.inputRowMeta.getFieldNames()));
for(String field: fieldNames){
sql += String.format("\"%s\" = \'%s\' AND ", field, get(Fields.In, field).getString(in));
get(Fields.Out, field).setValue(out, get(Fields.In, field).getString(in));
}
sql = sql.substring(0, sql.length()-4);
sql += ";";
Resulting in a column like this:
SELECT keys, from, the, table FROM SCHEMA.TABLE WHERE "unknown_field" = 'value' AND "unknown_field_1" = '0';
Now, that's all good until I receive a non String type from the SELECT, where I can't do get(Fields.In, field).getString(in)
since it returns
Conversion error: field Integer(9): There was a data type error: the data type of java.lang.String.object [0] does not correspond to value meta [Integer (9)]
Can you change every unspecified field's meta type? If not, is there a way to cast every non String field type within the custom Java Class to String?

SQL query does not return data

I am developing a SAP program to obtain information about a reference from the material table (MARA).
First I take certain references and then using a loop I need to make other query for every iteration:
SELECT
MARA~BISMT
FROM mara
WHERE mara~matnr = #ref
INTO #var.
I know that the problem is that the types conflict (mara~matnr is characters and ref is string), how can I convert both to the same type and see the results?
You can also use ABAP string templates instead of conversion exits suggested by mkysoft:
DATA: ref TYPE string VALUE '2'.
ref = |{ CONV matnr( ref ) ALPHA = in }|.
SELECT SINGLE bismt
FROM mara
WHERE matnr = #ref
INTO #DATA(var).
You can use field symbol for dynamic type and CONVERSION_EXIT_ALPHA_INPUT function module for formatting value for db.
TABLES: mara.
DATA: ref TYPE string,
var TYPE string.
FIELD-SYMBOLS: <fs_ref> TYPE any.
ref = '11'.
ASSIGN ('mara-matnr') TO <fs_ref>.
CHECK sy-subrc IS INITIAL.
<fs_ref> = ref.
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = <fs_ref>
IMPORTING
output = <fs_ref>.
SELECT SINGLE mara~bismt
FROM mara
INTO #var
WHERE mara~matnr = #<fs_ref>.

How to escape ampersand in message text?

I created a message class which contains the following text
No K&C Data available for &1
DATA ls_return TYPE bapiret2.
DATA lv_par1 TYPE sy-msgv1 .
lv_par1 = '123456' .
CALL FUNCTION 'BALW_BAPIRETURN_GET2'
EXPORTING
type = 'I'
cl = 'Z_MY_MESSAGE_CLASS'
number = 021
par1 = lv_par1
IMPORTING
return = ls_return.
WRITE ls_return-message .
The output of the small example programm will be
No K123456C Data available for 123456
but should be
No K&C Data available for 123456
So how do I escape(?) or change the entry of my message class?
You need use it as couple like below:
No K&&C Data available for &1

READ TABLE WITH TABLE KEY does not find record

I'm trying to use the class /ui5/cl_json_parser for parsing a JSON string.
The following code snippet reproduces the problem:
REPORT ztest_json_parse.
DATA: input TYPE string,
output TYPE string,
json_parser TYPE REF TO /ui5/cl_json_parser.
input = '{"address":[{"street":"Road","number":"545"},{"street":"Avenue","number":"15"}]}'.
CREATE OBJECT json_parser.
json_parser->parse( input ).
json_parser->print( ).
output = json_parser->value( path = '/address/1/street' ).
WRITE output.
The print method shows the correct parsed JSON string, but the output variable is always empty.
I have traced the code down to the method VALUE of the class /UI5/CL_JSON_PARSER, at line 15, which contains:
read table m_entries into l_entry with table key parent = l_parent name = l_name.
In the debugger, I can see that l_parent = '/address/1' and l_name = 'street', and that the internal table m_entries contains a record with parent = '/address/1' and name = 'street'. Nevertheless the READ statement always returns sy-subrc = 4 and does not find anything.
Can anyone help?
First: Do not use /ui5/cl_json_parser class, it is intended for internal use ONLY and has no reliable documentation
Secondly, here is the sample how you can fetch street value from the first element of your JSON:
DATA(o_json) = cl_abap_codepage=>convert_to( '{"address":[{"street":"Road","number":"545"},{"street":"Avenue","number":"15"}]' ).
DATA(o_reader) = cl_sxml_string_reader=>create( o_json ).
TRY.
DATA(o_node) = o_reader->read_next_node( ).
WHILE o_node IS BOUND.
DATA(op) = CAST if_sxml_open_element( o_node ).
LOOP AT op->get_attributes( ) ASSIGNING FIELD-SYMBOL(<a>).
DATA(attr) = <a>->get_value( ).
ENDLOOP.
IF attr <> 'street'.
o_node = o_reader->read_next_node( ).
ELSE.
DATA(val) = CAST if_sxml_value_node( o_reader->read_next_node( ) ).
WRITE: '/address/1/street =>', val->get_value( ).
EXIT.
ENDIF.
ENDWHILE.
CATCH cx_root INTO DATA(e_txt).
ENDTRY.
As far as I know, there is no class in ABAP that allows fetching single JSON attributes like XPath.
Certainly agree with Suncatcher on avoid UI5 Json parser.
If you dont control/know the structure of the source data, Suncatchers answer is good.
However,
if you know the basic structure of the source JSON and you must, if you plan to access the first address row, fieldname street .
AND you can have the source provided using uppercase variable names then you can use the so called identity transformation.
types: begin of ty_addr,
street type string,
number type string,
end of ty_addr.
types ty_addr_t type STANDARD TABLE OF ty_addr.
DATA: input TYPE string,
ls_addr TYPE ty_addr,
lt_addr type ty_addr_t.
input = '{"ADDRESS":[{"STREET":"Road","NUMBER":"545"},{"STREET":"Avenue","NUMBER":"15"}]}'.
CALL TRANSFORMATION id SOURCE XML input
RESULT address = lt_addr.
read table lt_addr index 1 into ls_addr.
WRITE ls_addr-street.

Create dynamic ABAP internal table

On selection screen, the user needs to insert a table name, and I need to get first 3 fields from that table and display them in an ALV for the output. What I understand from reading tutorials is that I need to call method cl_alv_table_create=>create_dynamic_table, but I don't know how to create the fieldcatalog.
DATA: t_newtable TYPE REF TO data,
t_fldcat TYPE lvc_t_fcat,
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = t_fldcat
IMPORTING
ep_table = t_newtable.
I assume that the table name which user enters is a data dictionary table (like SFLIGHT). If yes, then you can generate the field catalog as follows.
data : it_tabdescr type abap_compdescr_tab,
wa_tabdescr type abap_compdescr.
data : ref_table_descr type ref to cl_abap_structdescr.
ref_table_descr ?= cl_abap_typedescr=>describe_by_name( p_table ).
it_tabdescr[] = ref_table_descr->components[].
loop at it_tabdescr into wa_tabdescr.
clear wa_fieldcat.
wa_fieldcat-fieldname = wa_tabdescr-name .
wa_fieldcat-datatype = wa_tabdescr-type_kind.
wa_fieldcat-inttype = wa_tabdescr-type_kind.
wa_fieldcat-intlen = wa_tabdescr-length.
wa_fieldcat-decimals = wa_tabdescr-decimals.
append wa_fieldcat to it_fieldcat.
endloop.
Here, "p_table" is the selection screen parameter containing the table
name.