WIth Releases 7.02 and 7.03/7.31 (Kernelpatch 116) JSON is supported natively in ABAP by the following features:

  • JSON-XML is a special XML format that enables JSON data to be described using an XML representation. A new format, IF_SXML=>CO_XT_JSON, has been added to the sXML Library, which enables to handle JSON using JSON-XML.
  • The canonical JSON representation asJSON defines a mapping between ABAP types and JSON. This is used in serializations and deserializations using the identity transformation ID.
  • JSON data can be specified in various forms as an XML source in the statement CALL TRANSFORMATION and a JSON writer can be specified as target. The identity transformation ID supports JSON by using asJSON.

Example:

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( ).

“JSON to ABAP
text = `{“TEXT”:”Hello ABAP, I’m JSON!”}`.
CALL TRANSFORMATION id SOURCE XML text
                        RESULT text = text.

Addendum

Meanwhile, the documentation for ABAP and JSON is online. This blog is pointing to it.

To report this post you need to login first.

81 Comments

You must be Logged on to comment or reply to a post.

  1. Rüdiger Plantiko

    Horst,

    thanks for these good news. There already are quite a few ABAP implementations for JSON parsers / builders around, (see for example, my versions here: http://ruediger-plantiko.blogspot.ch/2011/09/ein-json-builder-in-abap.html and here: http://ruediger-plantiko.blogspot.ch/2010/12/ein-json-parser-in-abap.html ). But this implementation in the kernel will clearly be much more efficient.

    When I test your ABAP->JSON example above, the xstring JSON will contain JSON-XML. Is there a built-in way to get a “real” JSON string from JSON-XML, or do I have to write an own XSLT transformation to do this?

    Regards,
    Rüdiger

    (0) 
    1. Horst Keller Post author

      Hi Rüdiger,

      • For storing XML data in strings or internal tables, we recommend that you use byte strings or byte-like line types and the UTF-8 codepage for the representation of the data. This is why the methods of the sXML-Library use only xstring and not also string as the older iXML library does.
      • The methods CONVERT_FROM and CONVERT_TO from the class CL_ABAP_CODEPAGE can be used to transform character-like XML data or JSON data to a byte-like representation in accordance with a code page (and vice versa).
        • xstring = cl_abap_codepage=>convert_to( string ).
        • string =  cl_abap_codepage=>convert_from( xstring ).
      • Of course, you can write conveniently
        json = cl_abap_codepage=>convert_from(  writer->get_output( ) ).

      Cheers!

      Horst

      (0) 
      1. Horst Keller Post author

        PS: I guess I did not fully understand the question, but the answer is the same.

        In the above example, the xstring JSON does not contain JSON-XML but already the UTF-8 representation of JSON. In order to get JSON-XML, you would have to create an XML writer with cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 ) .

        Example:

        DATA text TYPE string VALUE `Hello JSON, I’m ABAP!`.
        DATA writer TYPE REF TO cl_sxml_string_writer.
        DATA json TYPE string.
        DATA xml TYPE string.

        “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 = cl_abap_codepage=>convert_from( writer->get_output( ) ).

        cl_demo_output=>write_json( json ).

        “ABAP to JSON-XML
        writer = cl_sxml_string_writer=>create). “standard type is if_sxml=>co_xt_xml10
        CALL TRANSFORMATION id SOURCE text = text
                                RESULT XML writer.
        xml = cl_abap_codepage=>convert_from( writer->get_output( ) ).

        cl_demo_output=>write_xml( xml ).

        cl_demo_output=>display( ).

        gives:

        {

        “TEXT”:”Hello JSON, I’m ABAP!”

        <asx:abap version=”1.0″ xmlns:asx=”http://www.sap.com/abapxml“>
        <asx:values>
          <TEXT>Hello JSON, I’m ABAP!</TEXT>
        </asx:values>
        </asx:abap>

        More Cheers!

        Horst

        (0) 
        1. Purayil T

          Hello Horst,

             I have a JSON string with deep structure

          {

          “is_model”:

               {

                    “t”:”DD”,

                    “i”:”Value for DD”

               },

          “is_qty”:

               {

                    “t”:”TX”,

                    “i”:”2016

               },

          “is_ctl”:

               {

                    “t”:”DD”,

                    “i”:”Single Apex”

               },

          “is_ctr_qty”:

               {

                    “t”:”TX”,

                    “i”:”2200″

               }

          }

          I need to convert this to XML for further processing, could you please help me how to get this is XML structure

          <object>

          <object name=”is_model“>

            <str name=”t”>DD</str>

            <str name=”i”>Value fo DD</num> 

          </object>

          .

          .

          .

          .

          </object>

          (0) 
            1. KIRAN RAJAN

              Hi Horst ,

              Thank you for the reply

              I am able to convert into XML by using the standard Class cl_idoc_xml1 ,but I am not able to convert to JSON-XML .It would be great if you can help me out in this issue.

              (0) 
                1. KIRAN RAJAN

                  Hi Horst,

                  My requirement is to convert the IDOC data into JSON format for that i tried the following things.

                  1) Convert the IDOC data into XML Format(by using the standardClass cl_idoc_xml1).Then to JSON Format.At this point of time i am stuck in converting XML to JSON and XML to JSON-XML format .

                  2) Check for Standard class to convert IDOC data into JSON format.However  I didn’t find any such class in ABAP.

                  (0) 
                  1. Horst Keller Post author

                    If there isn’t a standard class, you either have to write an XSLT that converts the XML to JSON-XML or to parse the XML into ABAP and render it as JSON-XML.

                    (0) 
                      1. Suhas Saha

                        HI Kiran,

                        Please post your query as a question. Remember to post the relevant code section of what you have tried so far.

                        BR,

                        Suhas

                        (0) 
      2. Rüdiger Plantiko

        Horst,

        thank you for your clarifications! Indeed, the writer contains the JSON string, not JSON-XML. I had made an error in my test code.

        I also appreciate the support in the debugger! If I look at a JSON string in the “XML Browser” view, I get it nicely transformed into an interactive structured display. Found out that there is an XSLT transformation SJSON2HTML responsible for this nice little feature…

        Regards,

        Rüdiger

        (0) 
  2. Stefan Riedel-Seifert

    Hello Horst,

    the information about the prerequisites about the sap system is nor precise enough. We drive 7.02 with dbsl patch level 314 and sp 06: because the corresponding interfaces and classes does not recognize the type if_sxml~co_xt_json.

    I have repaired IF_SXML and CL_SXML_WRITER and it works.

    Regards, Stefan

    (0) 
    1. Karthik Babu

      Hi Stefan,

      I’m facing the same issue. Can you please eloborate on what you did to fix the issue. You stated that you have repaired the classes. How did you repair them?

      Thanks,
      Karthik

      (0) 
        1. Karthik Babu

          Hi Horst,

          Thanks for your response. That note is not compatible with our instance of SAP. The problem that I’m facing is, I’m getting a dump during the execution of the statement

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

          I’m getting the dump for the exception CX_SXML_INTERNAL_ERROR, and only for the type IF_SXML=>CO_XT_JSON and not for other 3 types.

          Any help is appreciated.

          Thanks,

          Karthik

          (0) 
          1. Horst Keller Post author

            Hi Kathrik,

            JSON support is possible in the basis releases described in note 1648418 if you run on the 7.20-kernel described in note 1650141.

            From the error I guess that you have the right ABAP release but not the right kernel release.

            Best

            Horst

            (0) 
            1. Karthik Babu

              Hi Horst,

              Thanks for your reply.

              Our instance of server:

              kernel release 720
              patch level 100
              basis release 720
              sp level 0012
              abap release same as basis

              I checked importing the notes but SNOTE throws that the notes cannot be implemented. Please help me regarding this.

              Thanks,

              Karthik

              (0) 
    2. Alexander Claus

      Hi Stefan,

      I’m also interested in how to “repair” these classes. Do you mean one has to activate some “hidden” stuff or reimplement missing functionality?

      Thanks.

      Alexander

      (0) 
  3. Rüdiger Plantiko

    Horst,

    I am now trying to understand how references are handled. I saw that the references need to have a built-in or DDIC type – not a local or adhoc type – otherwise XSLT throws a “technical error” (which could be surpressed with “options technical_type = ‘ignore'”, but the corresponding data object would be ignored).

    I have a table of named references of arbitrary data objects (actually, I defined this type as a DDIC type, but I write it here as if it were a local type):

    types: begin of ty_data,

      name type string,

      value type ref to data,

    end of ty_data,

    ty_data_tab type hashed table of ty_data_tab,

    and pass it to an XSLT transformation

    data: lt_data type ty_data_tab.

    call transformation zdata

       source

          data = lt_data

       result xml lo_json.

    The transformation should dereference these data, the result being a hash of named data:

      { “name1”: … the JSON representation of data object name1 here …,

        “name2”: …

         }

    The only solution I currently see is to do the derefencing in ABAP using the ->* operator, to call the identity transformation in a loop for each dereferenced data object, and to compose the enclosing JSON object from these parts manually.

    Or is there a way to do this dereferencing inside of an XSLT transformation? This would open the way for mixing the built-in canonical transformation ABAP->JSON with own templates inside of an XSLT transformation. Which would be much more elegant and efficient than the “solution” calling N times the identity and doing string concatenation in ABAP.

    Regards,

    Rüdiger

    (0) 
    1. Horst Keller Post author

      Hi Rüdiger,

      An XSL-transformation always transforms from XML to XML. What you have to know, is the format of the XML data, your XSL-transformation works with.

      ABAP-Source:

      If you use CALL TRANSFORMATION with an XSL-transformation in order to transform ABAP data, the trick is that the ABAP data are always serialized into asXML and that the XSL-transformation works with that format, i.e. you must write a transformation that handles the asXML data.

      JSON-Target:

      Now for JSON.  XSLT does not know JSON. Here, the trick is that there is a SAP-specific mapping from XML to JSON called JSON-XML. If you specify a JSON-writer as target of CALL TRANSFORMATION, the XSLT must produce JSON-XML that is then  transformed to JSON by the writer.

      Putting it together:

      Your XSLT accesses the asXML representation of the connected ABAP data and must transform it to JSON-XML.

      So, as first step, call transformation ID for your ABAP data with an XML target in order to examine the asXML data that you have to handle. Then write an XSLT that transforms these asXML data to the JSON-XML that represents the JSON data you want to achieve. Applying that XSLT to your ABAP data with a JSON-writer as target gives the desired result.

      For information about JSON-XML see http://scn.sap.com/people/horst.keller/blog/2013/04/11/json-xml-saps-xml-representation-of-json

      Best

      Horst

      (0) 
      1. Rüdiger Plantiko

        Horst,

        thanks for your answer. Of course, XSLT maps XML to XML. I knew that.

        In my question, the source was ABAP data, which means that the XML source format is asXML implicitly.

        Also, in my question, the target format was a lo_json string writer, which means that the target XML format is implicitly asJSON.  So I am speaking of an XSLT transformation asXML to asJSON. So the XSLT transformation will produce a tree consisting of <object>, <str>, <array> … elements and the like.

        It is not necessary, as you wrote, that I first have to call the identity transformation explicitly, and in a second transformation to map the XML to JSON. Instead, I can directly work in one and only one XSLT transformation on the ABAP data, assuming them in asXML notation, and I can directly in this same XSLT transformation produce an asJSON XML output. This works fine in the non-reference case, and I have already developped various transformations of this type.

        My only problem is with data references. Let me give you a simple example.

        When you run the following test with a sample concrete “ref to” data object,

        method test.

        data: lo_json type ref to cl_sxml_string_writer,
                 lt_t000 type ref to cts_t000_tab,
                 lv_json type xstring.

           create data lt_t000.
           select * from t000 into table lt_t000->*.

           lo_json = cl_sxml_string_writer=>create( if_sxml=>co_xt_json ).
           call transformation id
             options
               data_refs = ‘heap-or-create’
             source
               data     = lt_t000
             result xml
               lo_json.

           lv_json = lo_json->get_output( ).
           break-point.
        endmethod.

        Then you get the following JSON output:

        {

          “DATA”: { “%ref”: “#d1” },

          “%heap”: {

            “d1”: {

              “%type”: “dic:CTS_T000_TAB”,

              “%val”: [

                {

                  “MANDT”: “000”,

                  “MTEXT”: “SAP AG Konzern”,

                  “ORT01”: “Walldorf”,

                  “MWAER”: “EUR”,

                  “ADRNR”: “”,

                  “CCCATEGORY”: “S”,

                  “CCCORACTIV”: “2”,

                  …

        Actually, the impicit XML asJSON output is

        <?xml version=”1.0″ encoding=”utf-8″?>

        <object>

        <object name=”DATA”>

        <str name=”%ref”>#d1</str>

        </object>

        <object name=”%heap”>

        <object name=”d1″>

        <str name=”%type”>dic:CTS_T000_TAB</str>

        <array name=”%val”>

        <object>

        <str name=”MANDT”>000</str>

        <str name=”MTEXT”>SAP AG Konzern</str>

        <str name=”ORT01″>Walldorf</str>

        … and so on

        So the ABAP->JSON converter is able to deserialize the data and to produce the fragment

        <object>

          <str name=”MANDT”>000</str>

          …

        and so on.

        I am looking for an XSLT transformation ZDATA which produces the actual data to which the reference points, in a generic way, i.e. independent of the actual data type. (So I want to dereference the data object inside of the XSLT transformation.) In the example, I want to produce as part of the result the following JSON array

        [

                {

                  “MANDT”: “000”,

                  “MTEXT”: “SAP AG Konzern”,

                  “ORT01”: “Walldorf”,

                  “MWAER”: “EUR”,

                  “ADRNR”: “”,

                  “CCCATEGORY”: “S”,

                  “CCCORACTIV”: “2”,

          ].

        Of course, as you proposed, I could evaluate the asABAP XML source fragment located below the asx:heap node (given by the XPath expression /asx:abap/asx:heap/*[@id = substring(./@href,2)] where the current node in asx:data is of reference type).

        But then I should explicitly program the cases: Is this a table, a structure, a simple data object? Or is it nested (if yes: do recursion…)? And all this logic has obviously already been implemented in the ABAP -> JSON converter: As you see in the example, the %val element of the heap section already contains what I am looking for.

        I hope that I could explain more clearly what I am looking for.

        Thanks for having a second look at this.

        Regards,

        Rüdiger

        (0) 
        1. Horst Keller Post author

          Hi Rüdiger,

          You say:

          “Also, in my question, the target format was a lo_json string writer, which means that the target XML format is implicitly asJSON.  So I am speaking of an XSLT transformation asXML to asJSON.”

          No, that is not the case. When using a JSON writer as a target format, the target XML format is not implicitly asJSON. The target format can be any JSON-XML and your transformation defines how to create it. asJSON is produced by the predefined transformation ID and you only see it when using transformation ID. If you use transfromation ID to serialize ABAP data to a JSON writer, conceptually first asXML is produced, second this is converted to asJSON-XML and third this is passed to the JSON Writer. In reality this is done in one step. But asJSON is generally not needed for self-written transformations, where you have to work with JSON-XML instead.

          You say:

          “It is not necessary, as you wrote, that I first have to call the identity transformation explicitly, and in a second transformation to map the XML to JSON.”

          I didn’t want to say that. What I wanted to say is that you have to look at the implicitly created asXML first and write an XSLT that converts that XML to the JSON-XML that you want to have. Of course you don’t need this intermediate step later on.

           

          You say:

          “And all this logic has obviously already been implemented in the ABAP -> JSON converter”.

          Sure, asJSON defines a mapping of all ABAP types to JSON including reference variables. For the asJSON representation of anonymous data objects and class instances (objects), which are addressed using references in reference variables, a reference mechanism is used like in asXML. Since JSON does not has any syntax for references, an SAP-specific reference mechanism based on asXML is used, where named reference variables are displayed as object components, whose content is a key for the referenced objects and the referenced objects are stored as object components in the object %heap.

          But this is the predefined ABAP to JSON mapping! What you want to achieve is a selfdefined ABAP to JSON mapping including a derserialization and for this, you must  either evaluate the asXML in your transformation yourself or deserialize the ABAP data before transforming them.

          Best

          Horst

          (0) 
          1. Rüdiger Plantiko

            “Also, in my question, the target format was a lo_json string writer, which means that the target XML format is implicitly asJSON.  So I am speaking of an XSLT transformation asXML to asJSON.”

            No, that is not the case. When using a JSON writer as a target format, the target XML format is not implicitly asJSON.

            Horst, I have used the wrong term, sorry for that. The target format of a transformation with a JSON writer as recipient is an XML dialect consisting of <object>, <array>, <str>, … elements. I wrongly thought the name for this dialect would be asJSON. As you corrected, this was the wrong name. Let’s call it SAP-JSON-XML.

            So I understand your reply that, unfortunatly it’s not possible to reuse the code which maps asXML ABAP data (is this the right name? Please don’t be angry with me if it’s the wrong name, you know what I mean) to the canonical SAP-JSON-XML tree fragment in custom XSLT transformations.

            Thanks for the answer anyway.

            Regards,

            Rüdiger

            (0) 
            1. Horst Keller Post author

              Hi Rüdiger,

              To my knowledge you cannot reuse the internal (kernel) functions that create asJSON from ABAP data. It is the same as for XML. There, you can also not reuse the (kernel) functions that create the asXML that is used implicitly or explicitly (when using ID).

              Kind regards

              Horst

              (0) 
  4. Alessandro Spadoni

    Very interesting blog , thank you!

    one question :

    in JSON to ABAP

    text = `{“TEXT”:”Hello ABAP, I’m JSON!”}`.

    CALL TRANSFORMATION id SOURCE XML text

                            RESULT text = text.

    I don’t need to specify that XML source is a JSON string , does it recognize just parsing the string?

    thank you

    Alessandro

    (0) 
  5. Rüdiger Plantiko

    Horst,

    I wonder how to convert ABAP to Booleans:

    How can i produce the JSON object

    { “FLAG”: true }

    from ABAP data. Is there a special data type which will be interpreted as Boolean? I can only produce

    { “FLAG” : “X” }    ( using data element FLAG for the component FLAG)

    and

    { “FLAG” : “true” }   (using elementary data type STRING for the component FLAG)

    which is not what I want.

    Thanks for an answer.

    Rüdiger

    (0) 
    1. Horst Keller Post author

      Hi,

      ABAP does not have a Boolean type. Therefore, transformation ID that produces asJSON cannot produce a JSON Boolean directly.

      Option 1:

      There is a JSON-XML representation for JSON Booleans:

      Boolean values

      true <bool>true</bool>

      false <bool>false</bool>

      http://scn.sap.com/people/horst.keller/blog/2013/04/11/json-xml-saps-xml-representation-of-json

      You have to write or use a transformation that converts the asXML of ABAP_BOOL into the above JSON-XML.

      Option 2:

      Use the domain XSDBOOLEAN (http://help.sap.com/abapdocu_731/en/index.htm?url=abenabap_xslt_asxml_schema.htm ). ABAP values typed with with data types of that domain are represented as real JSON Booleans when converted to JSON with ID.

      Example:

      DATA:

              BEGIN OF boolean,

                ab_true   TYPE abap_bool

                          VALUE abap_true,

                ab_false  TYPE abap_bool

                          VALUE abap_false,

                xsd_true  TYPE xsdboolean

                          VALUE abap_true,

                xsd_false TYPE xsdboolean

                          VALUE abap_false,

              END OF boolean.

          DATA(writer) = cl_sxml_string_writer=>create(

            type = if_sxml=>co_xt_json ).

          CALL TRANSFORMATION id SOURCE boolean = boolean

                                 RESULT  XML writer.

          DATA(json) = writer->get_output( ).

      Best

      Horst

      (0) 
      1. Rüdiger Plantiko

        Horst,

        thanks for the answer. The XSDBOOLEAN type is a practical option, it saves you the work of writing an own transformation, you can use the identical transformation instead. It works well on  our SAPKB70211 system, as I just tested. 

        Thanks & regards, Rüdiger

        (0) 
  6. Stefan Grosskinsky

    Hi Horst,

    is there a way to keep the internal ABAP representation of datatypes when transforming them?

    I have the use case that the user must be able to see how the values will look like in ABAP.

    E.g. ‘true’ should be an ‘X’; Date shold look like ‘20130701’ and not like ‘2013-07-01’.

    Kind regards

    Stefan

    (0) 
    1. Horst Keller Post author

      Hi Stefan,

      If you use the predefined transformation ID (see http://help.sap.com/abapdocu_740/en/index.htm?url=abenabap_json_trafo_id.htm ), you automatically work with asJSON (see http://help.sap.com/abapdocu_740/en/index.htm?url=abenabap_asjson.htm), where each ABAP type is mapped to a predefined JSON representation. With some special domains you can influence the mapping (see http://help.sap.com/abapdocu_740/en/index.htm?url=abenabap_asjson_schema.htm). If those don’t help, you have either to choose another ABAP type or write your own XSL or ST transformation.

      Best

      Horst

      (0) 
      1. Horst Keller Post author

        Ohkay, after direct communication, we learned that above suggestions do not really help.

        The task is to transform character-like data objects (especially d and t) as if they were strings.

        For the moment, the best way seems to be to create an intermediate ABAP data object where all character types are replaced by strings (using RTTS), assign the original object to the new one and to transform that one.

        Maybe there are better ideas?

        (0) 
  7. Selva A

    Hi Horst,

    Ours is 7.01 version.We are able to do the conversion between ABAP and JSON by applying the note you have provided in the thread. Now, we want to represent the JSON data to a byte-like representation in accordance with a code page.But the class : CL_ABAP_CODEPAGE is not available in our system .Due to that we are not able to achieve it .For achieving this in 7.01 system ,Is there any SAP note available for consuming the class : CL_ABAP_CODEPAGE from 7.01 ? or anyother alternative ways there?

    Thanks,

    Selva.

    (0) 
    1. Horst Keller Post author

      Hi Selva,

      CL_ABAP_CODEPAGE is a convenience class that encapsulates other classes (see docu). Before 7.02 you can (or must) use these classes directly.

      Best,

      Horst

      (0) 
  8. Frank Stødle

    Horst, in your example for JSON to ABAP, it seems that the variable text is only filled with data if the JSON field “TEXT” is uppercase. Is there a way to ensure that the transformation also works for mixed case JSON fields, such as “someText” and “Text”?

    (0) 
    1. Horst Keller Post author

      You are not the first one who asked.

      As an answer I’ve written an example for that use case ….

      😎

      PS: DEMO_JSON_XML_TO_UPPER used in the example looks as follows:

      <xsl:transform xmlns:xsl=http://www.w3.org/1999/XSL/Transform” version=“1.0”>
        <xsl:variable name=“smallcase” select=“‘abcdefghijklmnopqrstuvwxyz'”/>
        <xsl:variable name=“uppercase” select=“‘ABCDEFGHIJKLMNOPQRSTUVWXYZ'”/>
        <xsl:template match=“@* | node()”>
          <xsl:copy>
            <xsl:apply-templates select=“@* | node()”/>
          </xsl:copy>
        </xsl:template>
        <xsl:template match=“@*”>
          <xsl:attribute name=“name”>
            <xsl:value-of select=“translate(., $smallcase, $uppercase)”/>
          </xsl:attribute>
        </xsl:template>
      </xsl:transform>

      (0) 
      1. Frank Stødle

        Thanks a lot, Horst, that saved me lots of time 🙂

        Here is the code, I am looking for a field called “message” in the JSON:

        DATA: message type string.

        DATA(o_writer) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).

        CALL TRANSFORMATION demo_json_xml_to_upper SOURCE XML m_response RESULT XML o_writer.

        DATA(z_asjson) = o_writer->get_output( ).

        CALL TRANSFORMATION id source XML z_asjson RESULT message = message.

        I was thinking it might also be possible to use the parameter table of type ABAP_TRANS_PARMBIND_TAB, but that did not work out.

        (0) 
        1. Horst Keller Post author

          I was thinking it might also be possible to use the parameter table of type ABAP_TRANS_PARMBIND_TAB,

          I tried that too before writing the workaround 😛

          My idea would be to offer an appropriate transformation option

          that ignores the case of names. But up to now, my development buddies have not implemented it …

          (0) 
          1. Frank Stødle

            Yeah, that would make even more sense – JSON in ABAP is great (in 7.4 at least), but this particular thing is a weak spot. This is the kind of thing that my web developer friends make fun of  🙂

            (0) 
          2. Rüdiger Plantiko

            “But up to now, my development buddies have not implemented it …”


            With good reasons, I think. This would be half-baked. Think of the way back. How should ABAP know how to convert upper case to mixed? lower?  case.


            Use transformations. A mapping of element names is already available, there is no need for further development: in the form of own transformations, you can customize your mapping in whatever way.


            And  mapping only names is quite easy.


            Regards,

            Rüdiger


            (0) 
            1. Horst Keller Post author

              My development buddy, in fact the master mind behind all the modern ABAP stuff (XML, JSON, expression enabling, …), told me that Rüdiger’s answer is right one.  Chapeau!

              And that’s about that …

              (0) 
      2. Horst Keller Post author

        PPS: Someone who knows SAP-XML better than me (the master mind, see above) told me, that the transformation can be written shorter as follows:

        <xsl:transform xmlns:xsl=http://www.w3.org/1999/XSL/Transform
                      xmlns:sap=http://www.sap.com/sapxslversion=“1.0”>
          <xsl:template match=“@* | node()”>
            <xsl:copy>
              <xsl:apply-templates select=“@* | node()”/>
            </xsl:copy>
          </xsl:template>
          <xsl:template match=“@*”>
            <xsl:attribute name=“name”>
              <xsl:value-of select=“sap:upper-case(.)”/>
            </xsl:attribute>
          </xsl:template>
        </xsl:transform>

        (0) 
  9. Katan Patel

    Hi Horst,

    I am still a little new to simple transformations, but I have created some ABAP based restful APIs that consume and produce JSON for Javascript Web based applications and use simple transformations to deserialize the JSON to ABAP.


    One thing that is troubling me. As I understand it, you cannot guarantee the order that javascript object properties will be output during serialization to JSON.  More often than not they are processed in the order they were added to the object, but it should be assumed that the order is not guaranteed and it is down purely to the browser specific implementation.

    As for the simple transformations, as far as I can see, it is expected that the XML nodes must appear in the order that they are to be parsed. 

    If we cannot guarantee the order in which each browser implementation will serialize the Javascript Object to JSON, how can we handle that in the simple transformation.

    I’m struggling to find a solution, but thought I’d throw this out there in case any following this has come across the same issue and has any thoughts on the topic.

    Thanks,

    Katan

    (0) 
    1. Rüdiger Plantiko

      From the JSON standard: http://www.ietf.org/rfc/rfc4627.txt

      An object is an unordered collection of zero or more name/value pairs, where a name is a string and a value is a string, number, boolean, null, object, or array.

      So the order of object members cannot be guaranteed. This is in sync with the ECMAscript specification for object members: No guaranteed order. It’s only by chance if the implementors give you the order that you were expecting. You cannot rely on it, if you want to write robust software.

      From your description, I do not understand why you need this order. If you have good reasons for this, you’ll have to work with an array of objects instead, with other words you’ll have to change the JSON data structure.

      Regards, Rüdiger

      (0) 
      1. Katan Patel

        Hi Rudiger,

        This is exactly my point.  As I said before, object properties are unordered, but Simple Transformations expect order (unless I am mistaken and I hope I am).

        In cases where you need to conform to a standard (i.e. GeoJSON GeoJSON Specification ), you cannot just switch an object to be an array (to guarantee order) or you deviate from the standard. 

        It seems a fairly rudimentary thing to process things out of order to deal with deserializing object properties to ABAP, but perhaps I am wrong. 

        Regards,

        Katan

        (0) 
        1. Horst Keller Post author

          Hi Katan,

          In simple transformations, you do not address only by order but also by using names (see http://help.sap.com/abapdocu_740/en/index.htm?file=abenst_addressing_current_node.htm).

          This is especially the way for deserializing into structures (that are represented as unordered objects in JSON). See http://help.sap.com/abapdocu_740/en/index.htm?file=abenst_tt_value_structure.htm.

          So if you take the example from http://help.sap.com/abapdocu_740/en/index.htm?file=abenabap_st_json_table_abexa.htm, you can deserialize the JSON string also into an internal table where the components of the table line have another order, because its the name that counts and not the order.

               DATA: BEGIN OF carrier_wa_new,
                      carrid   TYPE scarrcarrid,
                      url      TYPE scarrurl,
                      carrname TYPE scarrcarrname,
                    END OF carrier_wa_new,
                    carrier_tab_new LIKE TABLE OF carrier_wa_new.

              CALL TRANSFORMATION demo_st_json_table
                                  SOURCE XML json
                                  RESULT carriers = carrier_tab_new.

          Hope this helps.

          Horst

          (0) 
            1. Katan Patel

              Hi Horst,

              Thanks for that.  I realised I was using the <tt:cond> without <tt:group>, which kind of worked.  But following the documentation in the link you posted, it’s now working perfectly.  I can control the occurences using “frq” and by nesting my group statements I can control things better for more complex scenarios using nested objects and arrays.

              Uwe – Thanks for letting me know about the id transform, I did not know that. I spent some time trying to parse a JSON object with an array property using the “id” transformation with little success. The example you created worked fine for object properties, but I could not get it to work using array elements

              I created the following simple example based on JSON arrays being translated to ABAP tables, but without any joy. I’m obviously missing something, but I can’t see anything in the help, to indicate what that may be…

              TYPES: BEGIN OF ty_num,

                                   num TYPE string,

                          END OF ty_num,

                          tty_nums TYPE STANDARD TABLE OF ty_num.

              START-OF-SELECTION.

                   DATA: test TYPE tty_nums,

                         json        TYPE string.

                   json = ‘{“nums”:[123,456]}’.

                   CALL TRANSFORMATION id SOURCE XML json

                                          RESULT nums = test.

              Thanks for your patience guys…

              Thanks,

              Katan

              (0) 
              1. Horst Keller Post author

                Hi Katan,

                Please be aware, that working with ID always means working with asXML/asJSON, see

                Identity Transformations for JSON and asJSON.

                If you want to deserialize JSON directly with ID into ABAP, the JSON must be in the asJSON format that matches the target ABAP data objects.

                JSON objects -> ABAP structures

                JSON arrays -> ABAP internal tables.

                The JSON format in your above example simply is not valid asJSON for the target object. It must be

                {

                “NUMS”:

                [

                  {

                   “NUM”:”123″

                  },

                  {

                   “NUM”:”456″

                  }

                ]

                }

                (your table line is structured and therefore, you must have an object for the structure component inside the array).

                JSON-data as well as XML-data that are not in asJSON/asXML format must be transformed into that format before deserializing. That’s exactly what you have to do when working with XSLT. When deserializing any JSON/XML with XSLT, the result of the transformation must be asJSON/asXML that is then so to say further deserialized into the ABAP objects implicitly by ID. -> Direct execution of ID only possible for asJSON/asXML.

                With Simple Transformations, there is no ID involved. The mapping between JSON/XML and ABAP data objects is done directly, because that’s the only purpose of ST. XSLT in contrast is a general language where ID and asJSON/asXML have to be introduced in order to connect to ABAP (see also “Serializations and Deserializations” in ABAP and XML – Wrapping it Up).

                Best

                Horst

                (0) 
        2. Uwe Fetzer

          And to your initial question: it works, the JSON transformation is working like a move-corresponding.

          TYPES: BEGIN OF ts_test,

                   f1 TYPE string,

                   f2 TYPE string,

                 END OF ts_test.

          DATA test TYPE ts_test.

          DATA json TYPE string.

          json = `{“TEXT”:{“F2″:”Field 2″,”F1″:”Field 1”}}`.

          CALL TRANSFORMATION id SOURCE XML json

                                 RESULT text = test.

          (0) 
          1. Horst Keller Post author

            I already thought nobody would ask about or mention the prdefined transformation ID regarding the order of structure components in JSON.

            But here it is and I can point to that documentation too 😉 :

            http://help.sap.com/abapdocu_740/en/index.htm?file=abenabap_asjson_abap_types_struc.htm

            In deserializations of the aJSON representation of a structure, the order of the object components is not important

            You see, the reason is the asJSON that is consumed by the Identitiy Transformations for JSON in the example above.

            But Katan was originally asking about Simple Transformations that are always self-written, not predefined. Those don’t need asJSON. One shouldn’t mix those things up.I have written a blog ABAP and XML – Wrapping it Up, that summarizes these facts for XML. For JSON it’s quiet similar.

            (0) 
  10. Frank Stødle

    Rüdiger, someone took it upon themselves to delete our whole exchange about missing attribute names in JSON-XML, but thanks for your help clearing up that issue.

    I have no idea what kind of moronic moderator would remove extremely useful content. This is the kind of incident that makes we wish we were all using StackExchange instead.

    -frank

    (0) 
    1. Rüdiger Plantiko

      Hi Frank,

      that’s disappointing news 😡

      The deleted discussion was not only helpful, but other users might take advantage of it also when google’ing for a solution to their problem.

      For the records (for the problem Googlers): You had written an ST transformation to map between an ABAP structure and a JSON string, which happened to work only one way: from JSON into ABAP. The other way round, it dumped. The cause was that the produced XML document was not conforming to the rules of JSON-XML (in this case the rule: children of <object> elements must have a name attribute). After fixing this, the ST worked both ways as intended. I added a link to my blog A Validator for JSON-XML

      and the online JSON-XML validator tool exposed therein ( A JSON-XML validator ).

      Regards,

      Rüdiger

      P.S.: I’ve made a copy of this text for further reuse if necessary.

      (0) 
      1. Frank Stødle

        For completeness, here is my transformation:

        <?sap.transform simple?>

        <tt:transform xmlns:tt="http://www.sap.com/transformation-templates">

          <tt:root name="MarkedWorkLocation"/>

          <tt:template>

            <object>

              <object>

                <str name="SAPSession">

                  <tt:value ref="MarkedWorkLocation.sapsession"/>

                </str>

                <num name="DrawingId">

                  <tt:value ref="MarkedWorkLocation.drawingid"/>

                </num>

                <num name="ZoomLevel">

                  <tt:value ref="MarkedWorkLocation.zoomlevel"/>

                </num>

                <array>

                  <tt:loop ref=".MarkedWorkLocation.Locations">

                    <object>

                      <str name="type">

                        <tt:value ref="$ref.type"/>

                      </str>

                      <object>

                        <num name="lat">

                          <tt:value ref="$ref.latlang.lat"/>

                        </num>

                        <num name="lng">

                          <tt:value ref="$ref.latlang.lng"/>

                        </num>

                      </object>

                    </object>

                  </tt:loop>

                </array>

              </object>

            </object>

          </tt:template>

        </tt:transform>

        and here is my JSON:

        {

            "MarkedWorkLocation": {

                "SAPSession": "ABC123",

                "DrawingId": 2983,

                "ZoomLevel": 7,

                "Locations": [

                    {

                        "type": "marker",

                        "latLang": {

                            "lat": 0.10078125,

                            "lng": 0.4881953125

                        }

                    },

                    {

                        "type": "marker",

                        "latLang": {

                            "lat": 0.30078125,

                            "lng": 0.4501953125

                        }

                    },

                    {

                        "type": "marker",

                        "latLang": {

                            "lat": 0.90078125,

                            "lng": 0.1501953125

                        }

                    }

                ]

            }

        }

        As Rüdiger pointed out, this would successfully convert JSON to ABAP structure, but it would not convert ABAP structure to JSON because some nodes are missing the name attribute. The second node from the top is missing name=”MarkedWorkLocation”, the array is missing name=”Locations”, and the second object inside the array is missing name=”latLang”.

        (0) 
        1. Venkatesh Ummarrao

          Hi Frank,

             now i am trying to convert json to abap . my JSON data is similar to above JSON data which you mentioned. Can you please give me a suggestion to solve convert that json into ABAP.

          Thank you!

          (0) 
    2. Suhas Saha

      I have no idea what kind of moronic moderator would remove extremely useful content.

      That would be me 🙁

      Someone had reported an abuse for that & tbh i was wondering why would you (of all people) get reported. But i should have listened to my instinct to check the content before deleting it. My apologies!

      Do you have any details of the content you had posted so that i can ask the SCN support team to reinstate it. 😐

      Sorry for the inconvenience.

      BR,

      Suhas

      PS – That’s why i don’t like to moderate while in the middle of doing something

      (0) 
      1. Frank Stødle

        Hi Suhas, sorry about the harsh wording, good of you to step forth 😀

        I can reply to Rüdiger’s post above with my original post (I have a copy) and also include Rüdiger’s explanation for the error. I think I’ll also sum up the learnings from these blog comments in a blog of it’s own when I get around to it.

        thanks

        Frank

        (0) 
      2. Rüdiger Plantiko

        Hi Suhas,

        thanks for your reply. I appreciate that you wrote this message.

        I hope that I don’t have a “spammer” image in the meantime, due to my vivid (a.k.a. garrulous) comments in the SCN 🙂

        Frank’s question would admittedly have been better placed in the ABAP development discussion area, but I don’t see the point in deleting it if it happens to be answered here.

        Regards,

        Rüdiger

        (0) 
        1. Suhas Saha

          I hope that I don’t have a “spammer” image in the meantime, due to my vivid (a.k.a. garrulous) comments in the SCN 🙂

          You are one of the few who keep the forum standards high. Your level of knowledge & expertise is second to none.

          So no way you fall in the “spammer” category 😛

          Frank’s question would admittedly have been better placed in the ABAP development discussion area

          Now i remember the sequence of events. Someone reported that it was not a blog & i did not X-check once before rejecting the content. My bad!

          (0) 
          1. Manish Kumar

            Someone reported that it was not a blog

            That would be me 🙂

            I think that transformation and resolution will help the community better if it is present as a solved question in forums.

            It often happens that questions asked in blog comments get rejected.

            (0) 
  11. Martin Ceronio

    Hello Horst,

    When trying to unmarshall deep JSON documents where all the keys are in lower case (I think represents multitudes of use cases), the transformation becomes problematic. Using (rtab) can only get you so far, and then arrays are still an issue.

    It would be nice if there were at least an option to interpret the keys in the JSON document in a case-agnostic way so that they map to ABAP fields automatically.

    Regards,

    Martin

    (0) 
    1. Rüdiger Plantiko

      Hello Martin,

      did you observe that the upper/lower case topic has been discussed extensively in the discussion thread to this blog?

      I see two cases here:

      • Eitheryou have control of the data format of the client performing the JSON requests to be processed by the SAP System. In this case, there is no problem at all: you can define the JSON format in such a way that the ID transformation works.
      • Or you don’t have control of that JSON data format. In that case, you will be very likely in a position that you have to write a transformation yourself: it will be a very rare case that the third-party software producer gives you a JSON data format that is directly processable by the identity transformation. It’s not only the upper / lower case of components, but also will the data usually be grouped into hash and array structures that do not match the ABAP DDIC data structures. So you have to write an XSLT, an ST, or propagate the as-ABAP-JSON-XML tree yourself in ABAP.

      So such an option “ignore-case” would be of very limited help in practice.

      Regards,

      Rüdiger

      (0) 
      1. Martin Ceronio

        Hello Rüdiger,

        Thanks, I suppose I should have scanned through the discussion to see whether this topic had been covered 🙂

        It is unfortunate that there is no easy way to handle JSON data in ABAP in spite of these advancements. (Depending of course on what one deems “easy”; writing transformations in addition to defining the data structures sounds like a lot of work to me).

        I suppose there is still scope for writing a custom parser/mapper to cater for some cases.

        Regards,

        Martin

        (0) 

Leave a Reply