Application Development and Automation 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: 
Read only

Transform complex ABAP internal tables to recursive nodes in XML

Former Member
0 Likes
1,230

Hi,

How to transform complex ABAP internal tables to recursive nodes in XML using XSLT?

Eg: ABAP data in internal table is like:

LEVELCOMPONENT
0P1
1C1
2C11
3C111
2C12
1C2
2C21
2C22
3C221
3C222

To be transformed to XML. Note - The number of levels is not fixed. There can be multiple children at different levels. A child at level 1 can be a parent for another child at level 2 and so on.

XML to look like

<P1>

         <C1>

                   <C11>

                               <C111>

                    <C12>

          <C2>

                    <C21>

                    <C22>

                                <C221>

                                <C222>

Any pointers are apprciated!

Regards
Deepthi

Hi,

How to transform complex ABAP internal tables to recursive nodes in XML using XSLT?

Eg: ABAP data in internal table is like:

LEVELCOMPONENT
0P1
1C1
2C11
3C111
2C12
1C2
2C21
2C22
3C221
3C222

To be transformed to XML. Note - The number of levels is not fixed. There can be multiple children at different levels. A child at level 1 can be a parent for another child at level 2 and so on.

XML to look like

<P1>

         <C1>

                   <C11>

                               <C111>

                    <C12>

          <C2>

                    <C21>

                    <C22>

                                <C221>

                                <C222>

Any pointers are apprciated!

Regards
Deepthi

3 REPLIES 3
Read only

JJosh
Active Participant
Read only

Ruediger_Plantiko
Active Contributor
0 Likes
795

The following transformation does the job.

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <ROOT>
      <xsl:apply-templates select="//item[LEVEL = 0]"/>
    </ROOT>
  </xsl:template>

  <xsl:template match="item">
    <xsl:variable name="level" select="LEVEL"/>
    <xsl:variable name="line_id" select="generate-id()"/>
    <xsl:variable name="children">
      <xsl:apply-templates select="following-sibling::item[LEVEL = $level+1][preceding-sibling::item[LEVEL = $level][1]/generate-id() = $line_id]"/>
    </xsl:variable>
    <xsl:element name="{NAME}">
      <xsl:if test="$children/*">
        <xsl:copy-of select="$children"/>
      </xsl:if>
    </xsl:element>
  </xsl:template>

</xsl:transform>

The test program below gives the expected output:

<?xml version="1.0" encoding="utf-8"?>

<ROOT>

<P1>

  <C1>

   <C11>

    <C111/>

    <C112/>

   </C11>

   <C12/>

  </C1>

  <C2>

   <C21/>

   <C22>

    <C221/>

    <C222/>

   </C22>

  </C2>

</P1>

</ROOT>

*&---------------------------------------------------------------------*
*& Report  Z_TEST_LEVEL_STRUC
*&---------------------------------------------------------------------*

report  z_test_level_struc.

types: begin of ty_node,
  level type i,
  name  type string,
  end of ty_node,
  ty_nodes type standard table of ty_node
    with non-unique default key.

start-of-selection.
  perform start.

* ---
form start.
  data: lt_nodes type ty_nodes,
        lo_doc   type ref to if_ixml_document.

  perform fill_nodes changing lt_nodes.

  lo_doc ?= cl_ixml=>create( )->create_document( ).

  call transformation z_test_level_struc
    source levels = lt_nodes
    result xml lo_doc.

  call function 'SDIXML_DOM_TO_SCREEN'
    exporting
      document    = lo_doc
    exceptions
      no_document = 1
      others      = 2.
  if sy-subrc ne 0.
    message id sy-msgid type 'I' number sy-msgno
      with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  endif.

endform.                    "start


* ---
form fill_nodes changing et_nodes type ty_nodes.
  data: ls_node  type ty_node.

  define _add_node.
    ls_node-level = &1.
    ls_node-name  = &2.
    append ls_node to et_nodes.
  end-of-definition.

  clear et_nodes.
  _add_node :
    0   'P1' ,
    1   'C1' ,
    2   'C11' ,
    3   'C111' ,
    3   'C112' ,
    2   'C12' ,
    1   'C2' ,
    2   'C21' ,
    2   'C22' ,
    3   'C221' ,
    3   'C222'.

endform.                    "fill_nodes

Read only

0 Likes
795

... or, slightly simplified, but functionally identical:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:strip-space elements="*"/>

  <xsl:template match="/">
    <ROOT>
      <xsl:apply-templates select="//LEVELS/*[LEVEL = 0]"/>
    </ROOT>
  </xsl:template>

  <xsl:template match="LEVELS/*">
    <xsl:variable name="level" select="LEVEL"/>
    <xsl:variable name="id" select="generate-id()"/>
    <xsl:element name="{NAME}">
      <xsl:apply-templates
        select="following-sibling::*[LEVEL = $level+1][preceding-sibling::*[LEVEL = $level][1]/generate-id() = $id]"/>
    </xsl:element>
  </xsl:template>

</xsl:transform>

  • This version works with DDIC line types, too, not only for local line types (as my test program above is using). For local types, the elements representing the table lines have the name "item". For DDIC types, these elements get the name of the DDIC line type instead. The transformation above eliminates the fixed name 'item' and uses '*' instead.
  • This holds for both transformations: The source structure may even have more than one level 0 entry. Therefore, everything is wrapped in a <ROOT> element. If, in your case, there is only one line of level 0, you can of course omit the wrapping <ROOT> element in the root template.
  • The XPath expression selects the set of all following siblings of the next line level, but only if they come before the next sibling having the current level.