Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with nested tables in XSLT transformation (XML to ABAP)

former_member589029
Active Contributor
0 Kudos

Hi Experts,

I am trying to do deep nesting in a XSLT transformation, but canu2019t get it to work. I also looked into Simple Transformations as an alternative but there the XML would have to be adjusted with the table tags for the loop which is definitely not an option for us.

Here is what I try to achieve, I built a basic example to show what it needs to do:

XML input File:


<?xml version="1.0" encoding="utf-8"?>
<HEADER>
  <PERSON>
    <NAME>Some Name</NAME>
    <ADDRESS>
      <NUMBER>111</NUMBER>
      <STREET>Test Street</STREET>
    </ADDRESS>
  </PERSON>
</HEADER>

The required ABAP output should be an internal table of the following type:

Table column 1: NAME

Table column 2: a table with the following structure:

Nested table column 1: NUMBER

Nested table column 2: STREET

I tried the following with a nested structure rather than a nested table which did work fine.

But once I change the XSLT to accept more than one ADDRESS and change the ABAP data structures to accept a table rather than a structure, the nested table data is just not filled in. Unfortunately I was not able to find any example in the SAP system or on the net that is using a nested table and does work. I also played around with the [Airplus example|https://www.sdn.sap.com/irj/sdn/wiki?path=/display/snippets/readdatafromXMLfileviaXSLT+program&] and was able to get that to work, but as soon as I introduce a nested tables on a level below the first level the data for that part is no longer populated.

What am I missing here?

Please find below the coding for the first example with the nested structure and the second example with the nested table (which doesnu2019t work).

ABAP report with nested structure (does work):


REPORT  zwa01_trans.

* Data Definitions --------------------------------------------------
TYPES: BEGIN OF ty_address,
         number TYPE char10,
         street TYPE char40,
       END OF ty_address.

TYPES: BEGIN OF ty_person,
         name    TYPE char20,
         address TYPE ty_address,
       END OF ty_person.

TYPES: BEGIN OF ty_xml_line,
         data(256) TYPE x,
       END OF ty_xml_line.

DATA: gt_in  TYPE TABLE OF ty_xml_line,
      gt_out TYPE TABLE OF ty_person.

CALL FUNCTION 'GUI_UPLOAD'
  EXPORTING
    filename = 'C:Documents and SettingswackerbauermMy Documents�6 - TEMP	estxml03.xml'
  TABLES
    data_tab = gt_in.

TRY.
    CALL TRANSFORMATION zwa01_test03
      SOURCE XML gt_in
      RESULT xml_output = gt_out.

  CATCH cx_xslt_exception.
    EXIT.
ENDTRY.

BREAK-POINT.

XSLT Program with nested structure (does work):


<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sap="http://www.sap.com/sapxsl" version="1.0">
  <xsl:template match="HEADER">
    <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
      <asx:values>
        <XML_OUTPUT>
          <PERSON>
            <NAME>
              <xsl:value-of select="PERSON/NAME"/>
            </NAME>
            <ADDRESS>
              <NUMBER>
                <xsl:value-of select="PERSON/ADDRESS/NUMBER"/>
              </NUMBER>
              <STREET>
                <xsl:value-of select="PERSON/ADDRESS/STREET"/>
              </STREET>
            </ADDRESS>
          </PERSON>
        </XML_OUTPUT>
      </asx:values>
    </asx:abap>
  </xsl:template>
</xsl:transform>

XML file (does work):


<?xml version="1.0" encoding="utf-8"?>
<HEADER>
  <PERSON>
    <NAME>Some Name</NAME>
    <ADDRESS>
      <NUMBER>111</NUMBER>
      <STREET>Test Street</STREET>
    </ADDRESS>
  </PERSON>
</HEADER>

Now I tried to expand this into a nested table and changed the XSLT as follows (does not return nested table values):


<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sap="http://www.sap.com/sapxsl" version="1.0">
  <xsl:template match="HEADER">
    <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
      <asx:values>
        <XML_OUTPUT>
          <PERSON>
            <NAME>
              <xsl:value-of select="PERSON/NAME"/>
            </NAME>
            <xsl:for-each select="ADDRESS">              <<<<INSERT
              <ADDRESS>
                <NUMBER>
                  <xsl:value-of select="PERSON/ADDRESS/NUMBER"/>
                </NUMBER>
                <STREET>
                  <xsl:value-of select="PERSON/ADDRESS/STREET"/>
                </STREET>
              </ADDRESS>
            </xsl:for-each>                              <<<<INSERT
          </PERSON>
        </XML_OUTPUT>
      </asx:values>
    </asx:abap>
  </xsl:template>
</xsl:transform>

After that I adjusted the ABAP code as follows:


REPORT  zwa01_trans.

* Data Definitions --------------------------------------------------
TYPES: BEGIN OF ty_address,
         number TYPE char10,
         street TYPE char40,
       END OF ty_address.

TYPES: BEGIN OF ty_person,
         name    TYPE char20,
         address TYPE ty_address occurs 0,    <<< ADDED OCCURS 0
       END OF ty_person.

This will add a nested table. The XML remained unchanged (It will just create one entry in the nested table). When executing the report now you can see that the table has been nested in the original structure, but is just empty. The curious thing is if I add ADDRESS more than once (e.g.) five times I get five empty lines in the nested table but they are all empty - so it does recognize the repeating tags, but just not transferring the data.

I also tried

address like standard table of gt_address

where gt_address is a data structure of number and street. I even created the structure in the dictionary, but that didnu2019t make a difference either.

I am out of ideas - anybody stumbled accros this and found a solution? I tested it in SAP 4.7 and ECC 6.0 with the same result.

Thank you,

Michael

1 ACCEPTED SOLUTION

Former Member
0 Kudos

Hi,

Did you test your XSLT program offline in Altova XML spy or any other similar tool ?

regards,

Advait

8 REPLIES 8

Former Member
0 Kudos

Hi,

Did you test your XSLT program offline in Altova XML spy or any other similar tool ?

regards,

Advait

0 Kudos

Hello Advait,

No I didn't test my XSLT in any offline tool, however I tested the XSLT in SE80 and it didn't return the data there either once I introduced xsl:for-each.

Michael

Former Member
0 Kudos

MIchael,

i think you have to use for-each with the XPATH preceding-sibling function.

Check the docu for "preceding-sibling" or "following-sibling".

Regards,

Gordon

0 Kudos

Hello Gordon,

I tried that as well in different flavors but unfortunately it didn't work either. In the meantime since we had to get this working we are using the SAP DOM object and some custom code to interpret the DOM object and create the appropriate internal table.

Thanks anyway,

Michael

uwe_schieferstein
Active Contributor
0 Kudos

Hello Michael

The following sample reports shows the transformation complex itab -> XML and XML -> complex itab.


*&---------------------------------------------------------------------*
*& Report  ZUS_SDN_XSLT_NESTED_ITAB
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*

REPORT  zus_sdn_xslt_nested_itab.


TYPE-POOLS: abap, trwbo.

DATA: gt_requests_pbo    TYPE trwbo_requests,  " complex itab
      gt_requests_pai    TYPE trwbo_requests.

DATA: gd_xml         TYPE string,
      gt_data        TYPE TABLE OF string.

DATA: go_xml_doc     TYPE REF TO cl_xml_document,
      gd_rc          TYPE i.

PARAMETERS:
  p_trkorr      TYPE trkorr DEFAULT 'EE2K902337'.



START-OF-SELECTION.

  CALL FUNCTION 'TR_READ_REQUEST_WITH_TASKS'
    EXPORTING
      iv_trkorr                = p_trkorr
    IMPORTING
*     ET_REQUEST_HEADERS       =
      et_requests              = gt_requests_pbo
    EXCEPTIONS
      invalid_input            = 1
      OTHERS                   = 2.
  IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
  ENDIF.


  BREAK-POINT.

  CALL TRANSFORMATION indent
    SOURCE itab = gt_requests_pbo
    RESULT XML gd_xml.

  CREATE OBJECT go_xml_doc.

  CALL METHOD go_xml_doc->parse_string
    EXPORTING
      stream  = gd_xml
    RECEIVING
      retcode = gd_rc.

  go_xml_doc->display( ).
  CALL METHOD go_xml_doc->export_to_file
    EXPORTING
      filename = 'C:\temp\ZZ_nested_itab.xml'
    RECEIVING
      retcode  = gd_rc.

  CLEAR: go_xml_doc.
  CLEAR: gd_xml.

  CREATE OBJECT go_xml_doc.
  CALL METHOD go_xml_doc->import_from_file
    EXPORTING
      filename = 'C:\temp\ZZ_nested_itab.xml'
    RECEIVING
      retcode  = gd_rc.

  CALL METHOD go_xml_doc->render_2_string
    EXPORTING
      pretty_print = 'X'
    IMPORTING
      retcode      = gd_rc
      stream       = gd_xml
*      size         =
      .

  CALL TRANSFORMATION indent
    SOURCE XML gd_xml
    RESULT itab = gt_requests_pai.


  IF ( gt_requests_pai = gt_requests_pbo ).
    MESSAGE 'Itabs are equal' TYPE 'S'.
  ELSE.
    MESSAGE 'Itabs are NOT equal' TYPE 'S'.
  ENDIF.



  IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*         WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
  ENDIF.


END-OF-SELECTION.

The XML for a sample transport request looks like this:


<?xml version="1.0" encoding="utf-8"?>
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
  <asx:values>
    <ITAB>
      <item>
        <H>
          <TRKORR>BEPK900061</TRKORR>
          <TRFUNCTION>T</TRFUNCTION>
          <TRSTATUS>R</TRSTATUS>
          <TARSYSTEM>BEP</TARSYSTEM>
          <KORRDEV>SYST</KORRDEV>
          <AS4USER>MH</AS4USER>
          <AS4DATE>2008-10-09</AS4DATE>
          <AS4TIME>15:03:20</AS4TIME>
          <STRKORR/>
          <AS4TEXT>test huwi</AS4TEXT>
          <AS4TEXT_FILLED>X</AS4TEXT_FILLED>
          <CLIENT>000</CLIENT>
          <TARCLIENT/>
          <CLIENTS_FILLED>X</CLIENTS_FILLED>
          <TARDEVCL/>
          <DEVCLASS/>
          <TARLAYER/>
          <E070M_FILLED/>
        </H>
        <OBJECTS>
          <item>
            <TRKORR>BEPK900061</TRKORR>
            <AS4POS>000001</AS4POS>
            <PGMID>R3TR</PGMID>
            <OBJECT>PMKS</OBJECT>
            <OBJ_NAME>P0001</OBJ_NAME>
            <OBJFUNC/>
            <LOCKFLAG/>
            <GENNUM/>
            <LANG/>
            <ACTIVITY/>
          </item>
          <item>
            <TRKORR>BEPK900061</TRKORR>
            <AS4POS>000002</AS4POS>
            <PGMID>R3TR</PGMID>
            <OBJECT>PMKS</OBJECT>
            <OBJ_NAME>P0002</OBJ_NAME>
            <OBJFUNC/>
            <LOCKFLAG/>
            <GENNUM/>
            <LANG/>
            <ACTIVITY/>
          </item>
          <item>
            <TRKORR>BEPK900061</TRKORR>
            <AS4POS>000003</AS4POS>
            <PGMID>R3TR</PGMID>
            <OBJECT>PMKS</OBJECT>
            <OBJ_NAME>P0006</OBJ_NAME>
            <OBJFUNC/>
            <LOCKFLAG/>
            <GENNUM/>
            <LANG/>
            <ACTIVITY/>
          </item>
        </OBJECTS>
        <KEYS/>
        <OBJECTS_FILLED>X</OBJECTS_FILLED>
        <ATTRIBUTES/>
        <ATTRIBUTES_FILLED/>
      </item>
    </ITAB>
  </asx:values>
</asx:abap>

<ITAB> is the entire complex itab whereas <OBJECTS> is the nested itab containing the object keys.

Your XSLT transformation has the create the same structure as above and then it should work.

Regards

Uwe

uwe_schieferstein
Active Contributor
0 Kudos

Hello Michael

I have solved this enigma: You need to replace XML_OUTPUT with ITAB in your XSLT transformation !!!!

Do not ask me why.

Below you see my sample report ZUS_SDN_XSLT_COMPLEX_ITAB followed by the XML file and the XLST transformation.


*&---------------------------------------------------------------------*
*& Report  ZWA01_TRANS
*&
*&---------------------------------------------------------------------*
*& Thread: Problem with nested tables in XSLT transformation (XML to ABAP)
*& <a class="jive_macro jive_macro_thread" href="" __jive_macro_name="thread" modifiedtitle="true" __default_attr="1086843"></a>
*&---------------------------------------------------------------------*

REPORT  zus_sdn_xslt_complex_itab.


* Data Definitions --------------------------------------------------
TYPES: BEGIN OF ty_address,
         number TYPE char10,
         street TYPE char40,
       END OF ty_address.


TYPES: BEGIN OF ty_person,
         name    TYPE char20,
         address TYPE STANDARD TABLE OF ty_address
                 WITH DEFAULT KEY,
       END OF ty_person.

TYPES: BEGIN OF ty_xml_line,
         data(256) TYPE c,
       END OF ty_xml_line.

DATA: go_xml_doc  TYPE REF TO cl_xml_document,
      gd_rc       TYPE i.

DATA: gt_in         TYPE TABLE OF ty_xml_line,
      gs_out        TYPE ty_person,
      gs_address    TYPE ty_address,
      gt_out TYPE TABLE OF ty_person
                  WITH DEFAULT KEY.


DATA: gt_xml        TYPE STANDARD TABLE OF string.
DATA: gd_xml        TYPE string,
      gd_xml_nested TYPE string.


START-OF-SELECTION.


**  <?xml version="1.0" encoding="utf-8"?>
**  <HEADER>
**    <PERSON>
**      <NAME>Some Name</NAME>
**      <ADDRESS>
**        <NUMBER>111</NUMBER>
**        <STREET>Test Street</STREET>
**      </ADDRESS>
**    </PERSON>
**  </HEADER>


**  CALL FUNCTION 'GUI_UPLOAD'
**    EXPORTING
**      filename = 'C:	empsdn_XSLTaddress_sample.xml'
**    TABLES
**      data_tab = gt_in.
  BREAK-POINT.



  CREATE OBJECT go_xml_doc.
  CALL METHOD go_xml_doc->import_from_file
    EXPORTING
      filename = 'C:	empsdn_XSLTaddress_sample.xml'
    RECEIVING
      retcode  = gd_rc.

  CALL METHOD go_xml_doc->render_2_string
    EXPORTING
      pretty_print = 'X'
    IMPORTING
      retcode      = gd_rc
      stream       = gd_xml
*       size         =
      .

  go_xml_doc->display( ).



  TRY.
      CALL TRANSFORMATION zus_sdn_complex_itab
        SOURCE XML gd_xml
        RESULT XML gd_xml_nested.

      CALL METHOD go_xml_doc->parse_string
        EXPORTING
          stream  = gd_xml_nested
        RECEIVING
          retcode = gd_rc.
      go_xml_doc->display( ).


**    <?xml version="1.0" encoding="UTF-8"?>
**    <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
**        <asx:values>
**            <ITAB>
**                <item>
**                    <NAME>Some Name</NAME>
**                    <ADDRESS>
**                        <item>
**                            <NUMBER>111</NUMBER>
**                            <STREET>Test Street</STREET>
**                        </item>
**                    </ADDRESS>
**                </item>
**            </ITAB>
**        </asx:values>
**    </asx:abap>


      call TRANSFORMATION id
        SOURCE XML gd_xml_nested
        result itab = gt_out.

    CATCH cx_xslt_exception.
      EXIT.
  ENDTRY.

XML sample file:


<?xml version="1.0" encoding="utf-8"?>
<HEADER>
  <PERSON>
    <NAME>Some Name</NAME>
    <ADDRESS>
      <NUMBER>111</NUMBER>
      <STREET>Test Street</STREET>
    </ADDRESS>
  </PERSON>
</HEADER>

XSL transformation:


<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="HEADER">
        <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
            <asx:values>
                <ITAB>
                    <xsl:for-each select="PERSON">
                        <item>
                            <NAME>
                                <xsl:value-of select="NAME"/>
                            </NAME>
                            <ADDRESS>
                                <xsl:for-each select="ADDRESS">
                                    <item>
                                        <NUMBER>
                                            <xsl:value-of select="NUMBER"/>
                                        </NUMBER>
                                        <STREET>
                                            <xsl:value-of select="STREET"/>
                                        </STREET>
                                    </item>
                                </xsl:for-each>
                            </ADDRESS>
                        </item>
                    </xsl:for-each>
                </ITAB>
            </asx:values>
        </asx:abap>
    </xsl:template>
</xsl:transform>

Regards

Uwe

Former Member
0 Kudos

Hi,

I think you will have to give the entire path of the ADDRESS.

i.e PERSON/ADDRESS


<xsl:for-each select="PERSON/ADDRESS">

Check this [Example program|http://www.w3schools.com/Xsl/xsl_for_each.asp] for further details on how to use for-each.

regards,

Advait

Former Member
0 Kudos

Hi, I had a similar problem. The main problem is how abap translate the internal table to xml:

"For each table a "item" object is created for each line in the table"

Example

Table def:

TYPES:   

      BEGIN OF t_w_detalle,

        grossamount                  TYPE string,

      END OF t_w_detalle,

       BEGIN OF t_w_items,

        posicionpedido  TYPE string,

        detalle         TYPE t_w_detalle OCCURS 0,

      END OF t_w_items,     

     

      END OF t_w_invoices,

        begin of t_w_xml,

          items TYPE t_w_items OCCURS 0,

       end of t_w_xml.

data: w_xml type t_w_xml.

Converted ABAP TABLE to XML:

<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">

 

  <asx:values>   

    <FACTURAEV32>

      <INVOICES>

        <ITEMS>

          <item>

            <POSICIONPEDIDO>1112577</POSICIONPEDIDO>

            <DETALLE>

              <item>

                <GROSSAMOUNT>3950.000000</GROSSAMOUNT>

              </item>

              <item>

                <GROSSAMOUNT>345.000000</GROSSAMOUNT>

              </item>

            </DETALLE>

          </item>         

        </ITEMS>

      </INVOICES>

    </FACTURAEV32>

  </asx:values>

</asx:abap>

In the xslt you can call it :

<-- CODE -->

<xsl:apply-templates select="INVOICES/ITEMS"/>

<-- CODE -->

           

<xsl:template match="ITEMS">

  <xsl:for-each select="item">    

    <-- CODE -->

   <xsl:apply-templates select="DETALLE"/>

  </xsl:for-each>

</xsl:template>

<xsl:template match="DETALLE">

  <xsl:for-each select="item">    

      <-- CODE -->

  </xsl:for-each>

</xsl:template>

U can also debug the xslt to have a detailed view of ur xml and how it's processed

Good luck !

pd: sorry for my english