$(function () { pageContext.i18n.modTalk = 'moderation talk'; pageContext.i18n.replyToComment = 'Reply'; pageContext.i18n.modTalkEmpty = 'moderation talk is empty'; pageContext.url.getModTalk = "/comments/%25ID%25/listModTalk.json"; pageContext.url.possibleCommentRecipients = "/comments/%ID%/possibleRecipients.json"; pageContext.url.commentEdit = '/comments/%25ID%25/edit.html'; pageContext.url.commentView = '/comments/%ID%/view.html'; pageContext.i18n.commentVisibility = { 'full': 'Viewable by all users', 'op': 'Viewable by the original poster', 'mod': 'Viewable by moderators', 'opAndMod': 'Viewable by moderators and the original poster', 'other': 'Advanced visibility', 'dialogTitle': 'Comment visibility', 'selectGroups': 'Visible to groups', 'selectOther': 'Other recipients', 'selectOriginalPoster': 'Original poster', 'selectModerators': 'Moderators', 'selectAssignees': 'Asked to answer users' }; pageContext.i18n.commentMenuLabels = { 'comment-edit': 'comments.menu.edit', 'comment-delete': 'comments.menu.delete', 'comment-convert': 'comments.menu.convert' };pageContext.i18n.answer= { bestAnswer: 'Best Answer', controlBar : { accept: 'Accept', unaccept: 'Unaccept', acceptCommand: 'Accept this answer as correct', cancelAcceptedCommand: 'Remove this answers accepted status' } }; window.croles = { u: false, op: false, m: false, og: false, as: false, ag: false, dc: false, doc: false, eo: false, ea: false }; tools.init({ q: { e: false, ew: false, eo: false, r: false, ro: false, d: false, dow: false, fv: false, c: false, co: false, p: false, tm: false , ms: false, mos: false }, n: { f: false, vf: false, vfo: false, vr: true, vro: true, c: false, co: false, vu: false, vd: false, w: false, wo: false, l: false }, c: { e: false, eo: false, d: false, dow: false, ta: false, tao: false, l: false }, a: { e: false, ew: false, eo: false, d: false, dow: false, a: false, aoq: false, ao: false, tc: false, tco: false, p: false, tm: false }, pc: croles }, { tc: true, nsc: true }); commandUtils.initializeLabels(); }); Skip to Content
avatar image
Former Member

Transforming ABAP internal table to JSON array (rather than object)

Is there an easy way to do this using the standard CALL TRANSFORMATION?  Here's what I'm doing:

"ABAP to JSON

   writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).

   CALL TRANSFORMATION id SOURCE ARRAY = lt_table

                          RESULT XML writer.

   lv_json = writer->get_output( ).

Now this generates JSON with an object named ARRAY in the proper format with sub-objects... but I don't want an object named ARRAY, I just want an unnamed array.

I searched through the documentation, the asJSON documentation seems to imply this should be possible, but doesn't specify any way to accomplish such a thing.  Leaving the name blank just generates an error.

Tried a few transformation OPTIONS as well, but none of them seem to accomplish this.

It's not a huge deal to use an object instead (although we're trying to squeeze every microsecond of performance out of this call), or even to just write my own darn transformation, but I guess I'm surprised SAP doesn't seem to support this functionality with CALL TRANSFORMATION.  Am I missing something?  Please tell me I'm missing something 😊

Add comment
10|10000 characters needed characters exceeded

  • Get RSS Feed

4 Answers

  • Best Answer
    avatar image
    Former Member
    Dec 03, 2014 at 04:11 PM

    I honestly can't remember why I asked this question (I think I was just confused about why the object needed a name but that turned out to not really be a problem), but here's what I ended up doing, in case it's helpful:

    EDIT: I noticed above someone asked about uppercasing the JSON -- I also had to do this because the REST service I was calling required it.  You can see below I actually convert back to string to do this, though there may be a more elegant solution.

    *for call to cl_http_client=>create_by_destination

       constants:  lc_dest    TYPE rfcdest  value 'MILEMAKER'.

    *local structures for handling input/output

       DATA: ls_postal_dist type ZST_POSTAL_DIST,

             ls_postal_conv type ZST_POSTAL_DIST,

             lt_postal_conv type ZTT_POSTAL_DIST,

    *for call to cl_http_client=>create_by_destination

             lo_CLIENT type ref to IF_HTTP_CLIENT,

             ls_RANDMCNALLY_JSON type ZST_RANDMCNALLY_JSON,

             lt_RANDMCNALLY_JSON type table of ZST_RANDMCNALLY_JSON,

             lv_HTTP_REASON type string,

             lv_HTTP_CODE type i,

    *JSON conversion

             lo_writer TYPE REF TO cl_sxml_string_writer,

             lv_json_in TYPE xstring,

             lv_json_out TYPE xstring,

             lv_json_string type string,

             lo_conv  type ref to CL_ABAP_CONV_IN_CE,

             lo_conv2 type ref to CL_ABAP_CONV_OUT_CE,

    *return parameters and error handlers

             lo_cxroot   TYPE REF TO cx_root,

             lv_message type string,

             lv_PAR1 LIKE  SY-MSGV1,

             lv_PAR2 LIKE  SY-MSGV2,

             lv_PAR3 LIKE  SY-MSGV3,

             ls_return type bapiret2.  "return structure

    [snip]

    *set request parameters

           CALL METHOD lo_client->request->SET_CONTENT_TYPE('application/json').

           CALL METHOD lo_client->request->SET_METHOD('POST').

    *convert data to JSON

           lo_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).

           CALL TRANSFORMATION id SOURCE routes = lt_RANDMCNALLY_JSON initial_components = 'suppress' RESULT XML lo_writer.

           lv_json_in = lo_writer->get_output( ).

    *attach data to body

           CALL METHOD lo_client->request->SET_DATA

             EXPORTING

               data = lv_json_in.

    *get JSON text in string format for testing

           CALL METHOD CL_ABAP_CONV_IN_CE=>CREATE

             EXPORTING

               INPUT       = lv_json_in

               ENCODING    = 'UTF-8'

               REPLACEMENT = '?'

               IGNORE_CERR = ABAP_TRUE

             RECEIVING

               CONV        = lo_conv.

           CALL METHOD lo_conv->READ

             IMPORTING

               DATA = lv_json_string.

    *send HTTP POST call to RandMcNally webservice

           call method lo_client->send

    * exporting  timeout = lc_timeout

            exceptions http_communication_failure  = 1

            http_invalid_state = 2

            http_processing_failed = 3

            others = 4.

           if sy-subrc <> 0.

             CALL METHOD lo_client->get_last_error

               IMPORTING

                 message = lv_message.

             CONCATENATE 'HTTP POST:' lv_message into lv_message.

             move lv_message to ls_return-message.

             append ls_return to return.

           endif.

    *receive data back

           CALL METHOD lo_client->receive

             EXCEPTIONS

               http_communication_failure = 1

               http_invalid_state         = 2

               http_processing_failed     = 3

               others                     = 4.

    *pass errors back, if any

           if sy-subrc <> 0.

             clear ls_return.

             ls_return-type = 'E'.

             CALL METHOD lo_client->get_last_error

               IMPORTING

                 message = lv_message.

             move sy-subrc to lv_json_string.

             CONCATENATE 'RECEIVE DATA:' lv_json_string lv_message into ls_return-message SEPARATED BY space.

             append ls_return to return.

           endif.

    *get the data (a table in JSON format) from response object

           clear lv_json_out.

           lv_json_out = lo_client->response->GET_DATA( ).

    *get the status of the response

           CALL METHOD lo_client->response->GET_STATUS

             IMPORTING

               CODE   = lv_HTTP_CODE

               REASON = lv_HTTP_REASON.

    *if response status code not 200 (OK), return error and cease processing

           if lv_http_code <> '200'.

             clear ls_return.

             ls_return-type = 'E'.

             move lv_http_code to lv_json_string.

             CONCATENATE 'GET STATUS:' lv_json_string lv_HTTP_REASON into ls_return-message SEPARATED BY space.

             append ls_return to return.

           ENDIF.

         catch cx_root into lo_cxroot.

         cleanup.

           ls_return-message = lo_cxroot->get_text( ).

           append ls_return to return.

       endtry.

    *close channel

       CALL METHOD lo_client->close

         EXCEPTIONS

           http_invalid_state = 1

           others             = 2.

    *trying to process after error sometimes results in short dump because lv_json_out contains something other than JSON

       if ls_return is not initial.

         return.

       endif.

       if lv_json_out is not initial.

    *convert JSON to string and make it UPPERCASE so that SAP can do transformation

         CALL METHOD CL_ABAP_CONV_IN_CE=>CREATE

           EXPORTING

             INPUT       = lv_json_out

             ENCODING    = 'UTF-8'

             REPLACEMENT = '?'

             IGNORE_CERR = ABAP_TRUE

           RECEIVING

             CONV        = lo_conv.

         CALL METHOD lo_conv->READ

           IMPORTING

             DATA = lv_json_string.

         TRANSLATE lv_json_string to UPPER CASE.

    *convert JSON back to xstring

         CALL METHOD CL_ABAP_CONV_OUT_CE=>CREATE

           EXPORTING

             ENCODING    = 'UTF-8'

             REPLACEMENT = '?'

             IGNORE_CERR = ABAP_TRUE

           RECEIVING

             CONV        = lo_conv2.

         lo_conv2->convert( EXPORTING data = lv_json_string

                      IMPORTING buffer = lv_json_out ).

    *convert our now UPPERCASE xstring to output table (JSON to ABAP)

         clear lt_randmcnally_json.

         lo_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).

         CALL TRANSFORMATION id OPTIONS value_handling = 'accept_decimals_loss'

                                SOURCE XML lv_json_out

                                RESULT routes = lt_RANDMCNALLY_JSON.


    [snip]

    Add comment
    10|10000 characters needed characters exceeded

    • Former Member Thomas Schmidt

      Hi Thomas, yes our output was this:

      {"ROUTES":[{"ORIGIN":{"CITY":"","STATE":"","ZIPCODE":"92880"},"DESTINATION":{"CITY":"","STATE":"","ZIPCODE":"90058"},"MILEAGE":0}],"INITIAL_COMPONENTS":"suppress"}

      The REST webservice then ignores ROUTES.

  • Dec 02, 2014 at 05:15 PM

    I have the same problem - the service I want to work with has a problem with the result from the default SAP json transformation and don't want the embracing object.

    CALL TRANSFORMATION id SOURCE source = it_tab RESULT XML lo_json_writer.

    rv_json_data = cl_abap_codepage=>convert_from( lo_json_writer->get_output( ) ).

    Result SAP Transformation in rv_json_data :

    {
       "SOURCE":[
          {
             "VBELN":"0000000001",
             "POSNR":"000010",
             "VKORG":"1111"
          },
          {
             "VBELN":"0000000001",
             "POSNR":"000020",
             "VKORG":"1111"
          }
       ]
    }


    Result wanted:

    [

       {

          "VBELN":"0000000001",

          "POSNR":"000010",

          "VKORG":"1111"

       },

       {

          "VBELN":"0000000001",

          "POSNR":"000020",

          "VKORG":"1111"

       }

    ]

    Is there any possiblity to exclude the object name and only get an array - or I really need to manipulate the string at the end ?

    Add comment
    10|10000 characters needed characters exceeded

    • Hi Kay - many thanks for this hint !

      this was a good tip 😊

      When I replaced the CL_TREX_JSON_SERIALIZER class with the transformation :

      * serialize info

      DATA l_serializer TYPE REF TO cl_trex_json_serializer.

      CREATE OBJECT l_serializer

        EXPORTING data = it_tab.

      l_serializer->serialize( ) .

      rv_json_data = l_serializer->get_data( ) .

      I get the needed JSON structure in rv_json_data - but now I have the problem that this serializer don't put the attribute in double quotes which is needed to be valid JSON :

      Result SAP CL_TREX_JSON_SERIALIZER Transformation in rv_json_data :

      [

         {

            vbeln:"0000000001",

            posnr:"000010",

            vkorg:"1111"

         },

         {

            vbeln:"0000000001",

            posnr:"000020",

            vkorg:"1111"

         }

      ]

      Result wanted:

      [

         {

            "vbeln":"0000000001",

            "posnr":"000010",

            "vkorg":"1111"

         },

         {

            "vbeln":"0000000001",

            "posnr":"000020",

            "vkorg":"1111"

         }

      ]

      And I would prefer to also uppercase the attributes - can I accomplish this somehow ???

      Best,

      Thomas

      Edit: I found out that this is a well known problem -> Serialize ABAP data into JSON format

  • Feb 18, 2015 at 10:14 AM

    You can write STs to achieve arrays from internal tables, there is an example in the documentation.

    Add comment
    10|10000 characters needed characters exceeded

  • Mar 16, 2015 at 03:25 PM

    Hello,

    Is there a way that I can the opposite, I get a JSON from somewhere with a service and now I want to transform the data to an ABAP internal table so I can save it to the database

    Thanks, Dren

    Add comment
    10|10000 characters needed characters exceeded

    • Former Member

      Yep, I did that in my code above (my RFC converts ABAP to JSON and then JSON to ABAP).  I'll repost that section here.  For some reason, ABAP doesn't like lowercase JSON so I had to convert it to uppercase.

      You could also use the deserializer I suppose, but I think the transformation is a lot simpler. YMMV.

      *convert JSON to string and make it UPPERCASE so that SAP can do transformation

           CALL METHOD CL_ABAP_CONV_IN_CE=>CREATE

             EXPORTING

               INPUT       = lv_json_out

               ENCODING    = 'UTF-8'

               REPLACEMENT = '?'

               IGNORE_CERR = ABAP_TRUE

             RECEIVING

               CONV        = lo_conv.

           CALL METHOD lo_conv->READ

             IMPORTING

               DATA = lv_json_string.

           TRANSLATE lv_json_string to UPPER CASE.

      *convert JSON back to xstring

           CALL METHOD CL_ABAP_CONV_OUT_CE=>CREATE

             EXPORTING

               ENCODING    = 'UTF-8'

               REPLACEMENT = '?'

               IGNORE_CERR = ABAP_TRUE

             RECEIVING

               CONV        = lo_conv2.

           lo_conv2->convert( EXPORTING data = lv_json_string

                        IMPORTING buffer = lv_json_out ).

      *convert our now UPPERCASE xstring to output table (JSON to ABAP)

           clear lt_randmcnally_json.

           lo_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).

           CALL TRANSFORMATION id OPTIONS value_handling = 'accept_decimals_loss'

                                  SOURCE XML lv_json_out

                                  RESULT routes = lt_RANDMCNALLY_JSON.