Saturday, May 26, 2012

Simple Transformation for XML in ABAP - Part III & some JSON on the side


This is just to explain a bit further on one of my comments from the earlier XML related post : Generate Simple Transformation for XML in ABAP - Part II.

There were a few questions regarding transforming ABAP ITABs with deep structures to XML and setting encoding ( other than default UTF-8 ) for the output XML etc.


Initial steps are similar to the example in my last XML related posts.
  1. For this example, a standard table type with complex structure is used. Accordingly you can create a ST program using editor :


  2. Generated ST Code [ Z_TEST_RAM ] is as below:

    <tt:transform xmlns:ddic="http://www.sap.com/abapxml/types/dictionary" xmlns:def="http://www.sap.com/abapxml/types/defined" xmlns:tt="http://www.sap.com/transformation-templates">
      <tt:root name="LDAP_TABLE" type="ddic:LDAPALTAB">
      <tt:template>
        <ldap_attributes>
          <tt:loop name="XALIAS0" ref=".LDAP_TABLE">
            <ldap_attribute>
              <name tt:value-ref="NAME">
              <vals>
                <tt:loop ref="VALS">
                  <value tt:value-ref="$REF.VAL">
                </value></tt:loop>
              </vals>
            </name></ldap_attribute>
          </tt:loop>
        </ldap_attributes>
      </tt:template>
    </tt:root></tt:transform>
    
    
  3. ABAP Sample Code is as below :
     REPORT z_test_ram_xml.
    
    * complex structure example
    DATA : lt_itab TYPE ldapaltab,
    wa_itab LIKE LINE OF lt_itab ,
    lt_val TYPE valtabc,
    wa_val LIKE LINE OF lt_val .
    
    DATA: gv_xml_xstring TYPE xstring.
    DATA: gv_final_xml_xstring TYPE xstring.
    
    * <<< Populate Example data in complex struture itab
    wa_itab-name = 'header1'.
    
    wa_val-val = 'Hi'.
    APPEND wa_val TO wa_itab-vals.
    wa_val-val = 'How r you'.
    APPEND wa_val TO wa_itab-vals.
    
    APPEND wa_itab TO lt_itab.
    *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    * This is the main ST call.
    CALL TRANSFORMATION z_test_ram
    SOURCE ldap_table = lt_itab[]
    RESULT XML gv_xml_xstring.
    *>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    * Now a Bit of cheating - to get the encoding we'll use standard XSLT ID
    * rather than ST - not required if you need Default UTF-8 from ST
    
    DATA :go_ixml TYPE REF TO if_ixml,
    go_stream_factory TYPE REF TO if_ixml_stream_factory,
    go_encoding TYPE REF TO if_ixml_encoding,
    go_resstream TYPE REF TO if_ixml_ostream.
    
    CONSTANTS: gc_encoding TYPE string VALUE 'UTF-16'. "or UTF-8 etc.
    
    go_ixml = cl_ixml=>create( ).
    go_stream_factory = go_ixml->create_stream_factory( ).
    go_encoding = go_ixml->create_encoding( character_set = gc_encoding byte_order = 0 ).
    go_resstream = go_stream_factory->create_ostream_XSTRING( gv_final_xml_xstring ).
    
    CALL METHOD go_resstream->set_encoding( go_encoding ).
    
    CALL TRANSFORMATION ID
    SOURCE XML gv_xml_xstring
    RESULT XML go_resstream.
    
    cl_salv_data_services=>download_xml_to_file(
    filename = 'C:\z_test_ram_xml_file.xml'
    xcontent = gv_final_xml_xstring ).
    
    

  4. Downloaded XML with encoding set as "UTF-16" is as below:
    <?xml version="1.0" encoding="UTF-16"?>
    <LDAP_ATTRIBUTES>
     <LDAP_ATTRIBUTE>
      <NAME>header1</NAME>
       <VALS>
        <VALUE>Hi</VALUE>
        <VALUE>How r you</VALUE>
       </VALS>
     </LDAP_ATTRIBUTE>
    </LDAP_ATTRIBUTES>

By the way, I was experimenting with an XML to JSON converter( rather JSONML ) that is compatible with XSLT-1.0 hence it can be used with ABAP XSLT . I've not tested it properly yet but just to add some information: The XSLT is written by @bramstein and the code can be taken from here . Some details are on this can be found here. Steps are as below :

  1. Created an XSLT program in XSLT_TOOL with Name(ID)  Z_RAM_TEST_XSLT_JSON .
    • For the XSLT, get the code from here .
    • Just changed a few lines due to some syntax issue, from this:
      <xsl:when test="(normalize-space($value) ne $value or string(number($value)) = 'NaN' or (substring($value , string-length($value), 1) = '.') or (substring($value, 1, 1) = '0') and not($value = '0')) and not($value = 'false') and not($value = 'true') and not($value = 'null')">
          <xsl:text>"</xsl:text>
          <xsl:call-template name="encode">
           <xsl:with-param name="input" select="$value"/>
          </xsl:call-template>
          <xsl:text>"</xsl:text>
         </xsl:when>
      
    • To :
      <xsl:when test="(normalize-space($value) != $value or string(number($value)) = 'NaN' or (substring($value , string-length($value), 1) = '.')
                                or (substring($value, 1, 1) = '0') and not($value = '0'))
                                and not($value = 'false')
                                and not($value = 'true') and not($value = 'null')">
          <xsl:text>"</xsl:text>
          <xsl:call-template name="encode">
           <xsl:with-param name="input" select="$value"/>
          </xsl:call-template>
          <xsl:text>"</xsl:text>
         </xsl:when>
      
  2. Added following piece of code at the end of the ABAP program (z_test_ram_xml) :
    [ Note that it might work directly from from ABAP Itab to JSON but there were some unwanted asx:abap tags appearing on the first line. That can be sorted out though. ]
     *<<<< Convert the output XML to JSON using XSLT
      DATA : gv_json_string TYPE STRING.
        CALL TRANSFORMATION  Z_RAM_TEST_XSLT_JSON 
        SOURCE XML gv_final_xml_xstring
    *    SOURCE ldap_table = lt_itab[]
        RESULT XML gv_json_string.
    
      WRITE : gv_json_string.
    
    
  3. Resultant JSONML is as below :
    ["LDAP_ATTRIBUTES",["LDAP_ATTRIBUTE",["NAME","header1"],["VALS",["VALUE","Hi"],["VALUE","How r you"]]]]
    
Warning : Please don't use above approach for any productive program without proper testing.  If you are looking for an ABAP/JSON library, for production use, then I would suggest to check ABAP JSON Library by Uwe Fetzer @se38 on SDN. Also just wanted to mention that Blogger's comment-section does not accept XML/HTML code hence you may need to escape any code before posting it in comments. [ Hint : search for "escape html tool online" in Google ]

Updated on 27/01/2013 :

Please refer to Horst Keller's Blog Post on SCN
Basically, you no longer need to try so much for JSON<->ABAP transformation as with new Releases 7.02 and 7.03/7.31 (Kernel-patch 116) JSON is supported natively in ABAP. Enjoy!.. and I hope you understand that these little improvements are big enablers :)


1 comment:

  1. Hello Ram,

    Thanks for these helpful blog for simple transformations. because of this i am able to generate xml file successfully. But i am having problem and i am unable to find solution.
    Let's say i am having deep structure created in SE11 (and that is also being used in call transformation) having one field 'Header' - deep structure and second field is 'Info' type table .

    Now if my xml is generated for multiple line items records in 'Info' table then all line items are showing under one main 'Info' node .

    i want to generate 'Info' node for my each line item.

    Do you have any idea how we can achieve this using simple transformation ?

    Thanks

    ReplyDelete

Info : Comments are reviewed before they are published. SPAMs are rejected.

Copyright