Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
gunther_stuhec
Advisor
Advisor

Introduction


It is quite often the case, to calculate the actual position of a line item or the number of elements in a target payload and write the results into specific element at the target payload.

For example, you need the ordinal number of a line item in E1EDP01/POSEX in a SAP IDoc purchase Order message (ORDERS.ORDERS05) or you need the number of total segments in the data element "0074" (Number of segments in the message) in the output of an UN/EDIFACT ORDERS message or in the data element "96" (Number of Included Segments) in the output of an ASC X.12 message.

Both, the ordinal number or number of segments, can't be currently expressed in the Mapping Guideline of the Integration Advisor. But this feature is already at the roadmap and should be delivered at approx. Q1/2021. See roadmap item: Constant functions in the mapping guideline.

In meanwhile, I can offer you a workaround in form of a XSLT script, which you can use after the mapping flow step. This blog is about this workaround.

Ordinal number for line items


Let's assume the company Big Fruit Trade (BFT) AG sends a SOAP based purchase order to the German trading partner Frucht und Gemuese (F&G) AG, and this trading partner wants to receive this purchase order as a SAP IDoc message based on the message type "ORDERS.ORDERS05". In this message, the data element "POSEX" in segment "E1EDP01" should have the ordinal number of each line item.

1.) Set POSEX to mandatory in target MIG


So that this "POSEX" element will be definitively created in the target payload, it is necessary to set the min. cardinality to 1 (mandatory) in the target MIG which represents the SAP IDoc structure (See following figure 1)


Figure 1: Set the min cardinality of POSEX element to 1.



2.) May set constant at POSEX in MAG


If you like, you can set a constant at the POSEX element at the target structure of the MAG. The constant could be for example a white space. The value is irrelevant. It will be substituted later on. It can be set for having the guarantee that the POSEX element will be created. But this is not necessary, because the POSEX element will be generated anyway, because of the set min. cardinality 1.


Figure 2: Set constant at element POSEX


The constant could be set, if you click on the action icon at the element POSEX and than you will get the menu item "Set Constant". This menu item will open a window in where you can enter the constant value.

3.) Create a XSLT Processing Script


The most important part is the following XSLT Processing Script, which should be used after the mapping step in the corresponding integration flow.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<!-- ============================================================================================= -->
<!-- Template: Enter the ordinal number in POSEX-->
<!-- ============================================================================================= -->
<xsl:template match="POSEX">
<POSEX>
<xsl:value-of select="count(preceding::POSEX)+1"/>
</POSEX>
</xsl:template>
<!-- ============================================================================================= -->
<!-- Template: Consume and produce remaining nodes -->
<!-- ============================================================================================= -->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Especially the template match="POSEX" is responsible for the setting the ordinal number, because the function count(preceding::POSEX) + 1 counts all preceding POSEX elements at the actual position at writes the result +1 into the element "POSEX".

4.) Insert the script into the corresponding integration flow


This script should be uploaded as an additional resource into the corresponding integration flow in where the other generated runtime artefacts of the Integration Advisor are used. It is also important to add an additional XSLT mapping flow step between the mapping flow step and the post-processing flow step in where this uploaded script has to be referenced (see following figure).


Figure 3: Additional flow step for the ordinal number script



5.) Deploy and test


After deploy and test of the integration flow, you should get the following result of an SAP IDoc ORDERS payload, if the source payload based on SOAP has two order items, The target payload should also have order items with a POSEX element in where you find the ordinal number.











Source Payload (SOAP) Target Payload (IDOC ORDERS)

<OrderRequest>
...
<Order>
...
<OrderItem>
<PurchaseOrderItemID>
10
</PurchaseOrderItemID>
<PurchaseOrderItemCategory>
0
</PurchaseOrderItemCategory>
<OrderItemText>
Large Apple Box
</OrderItemText>
<RequestedQuantity unitCode="PCE">
1.0
</RequestedQuantity>
...
</OrderItem>
<OrderItem>
<PurchaseOrderItemID>
20
</PurchaseOrderItemID>
<PurchaseOrderItemCategory>
0
</PurchaseOrderItemCategory>
<OrderItemText>
Oranges
</OrderItemText>
<RequestedQuantity unitCode="KGM">
5.0
</RequestedQuantity>
...
</OrderItem>
</Order>
</OrderRequest>


<?xml version="1.0" encoding="UTF-8"?>
<ORDERS05>
<IDOC BEGIN="1">
...
<E1EDP01 SEGMENT="1">
<POSEX>1</POSEX>
<PSTYP>0</PSTYP>
<MENEE>PCE</MENEE>
<PMENE>PCE</PMENE>
<CURCY>EUR</CURCY>
<E1EDP02 SEGMENT="1">
<BELNR>10</BELNR>
</E1EDP02>
<E1EDP20 SEGMENT="1">
<EDATU>2020-08-31</EDATU>
</E1EDP20>
<E1EDP19 SEGMENT="1">
<IDTNR>TG11_PH_CO21</IDTNR>
</E1EDP19>
<E1EDPT1 SEGMENT="1">
<E1EDPT2 SEGMENT="1">
<TDLINE>Large Apple Box</TDLINE>
</E1EDPT2>
</E1EDPT1>
</E1EDP01>
<E1EDP01 SEGMENT="1">
<POSEX>2</POSEX>
<PSTYP>0</PSTYP>
<MENEE>KGM</MENEE>
<PMENE>KGM</PMENE>
<CURCY>EUR</CURCY>
<E1EDP02 SEGMENT="1">
<BELNR>20</BELNR>
</E1EDP02>
<E1EDP20 SEGMENT="1">
<EDATU>2020-08-24</EDATU>
</E1EDP20>
<E1EDP19 SEGMENT="1">
<IDTNR>RMPI005</IDTNR>
</E1EDP19>
<E1EDPT1 SEGMENT="1">
<E1EDPT2 SEGMENT="1">
<TDLINE>Oranges</TDLINE>
</E1EDPT2>
</E1EDPT1>
</E1EDP01>
</IDOC>
</ORDERS05>


Segment counters


Especially in UN/EDIFACT based messages or ASC X12 based messages you need a segment counter. The principle is the same like described in the chapter "Ordinal number for line items". The following subchapter cover the specific parts.

1.) Relevant data elements in the MIGs


The data elements, in where you have to write the number of segments are in both cases, UN/EDIFACT and ASC X12, already mandatory. The following figures are showing the message trailers with the relevant data element and its cardinality. These data elements should be selected in the target MIG.


Figure 4: ASC X12 transaction trailer segment with data element 96



Figure 5: UN/EDIFACT message trailer segment with data element 0074


Like described before, you may set constants to these data elements in your mapping guideline.

2.) XSLT Script for getting the number of segments


Relevant is the XSLT script, which should be also placed after the mapping flow step and before the post-processing flow step. The following two examples displays the scripts for setting the number of included segments in ASC X12 messages and in UN/EDFACT messages.

The script for ASC X12 messages


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<!-- ============================================================================================= -->
<!-- Template: Enter the count of segments -->
<!-- ============================================================================================= -->
<xsl:template match="D_96">
<D_96>
<xsl:value-of select="count(//*[starts-with(name(), 'S_')])"/>
</D_96>
</xsl:template>
<!-- ============================================================================================= -->
<!-- Template: Consume and produce remaining nodes -->
<!-- ============================================================================================= -->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

The function count(//*[starts-with(name(), 'S_')]) counts all elements, which start with the prefix "S_" and writes it into the data element D_96. The prefixes S_ and D_ in the tag names are necessary, because the generated runtime artefacts follow the conventions as described in the international standard ISO/TS 20625:2002 which can be also used for XML based ASC X12 messages.

The script for UN/EDIFACT messages


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<!-- ============================================================================================= -->
<!-- Template: Enter the count of segments -->
<!-- ============================================================================================= -->
<xsl:template match="D_0074">
<D_0074>
<xsl:value-of select="count(//*[starts-with(name(), 'S_')])"/>
</D_0074>
</xsl:template>
<!-- ============================================================================================= -->
<!-- Template: Consume and produce remaining nodes -->
<!-- ============================================================================================= -->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

The only difference in comparison with XSLT script for ASC X12 messages is the data element tag D_0074 instead D_96.
2 Comments