kuhu jain
kuhu jain

Reputation: 43

XML to Fixed Length File Using XSLT (Complex Position Logic)

We have a requirement in which need to convert XML into Fixed Length File. First record is as header and after that we have actual records..From 2 record onwards we need to apply the logic which is mentioned below:
1.After length 45, consider 10 numbers 0000001000, what ever be the last digit we need to check and replace by following the below table:

      "For Positive Amount: (0000001000)   - (000000100{)             
      {= 0                                          
      A = 1                                       
      B = 2                                      
      c = 3                                      
      D = 4                                     
      E = 5                                      
      F = 6                                     
      G = 7                                      
      H = 8                                     
      I = 9 

I have not that much idea so created the small XSLT , request anyone please help on the same.

Input:

 <?xml version='1.0' encoding='utf-8'?>
<ZR>
<INPUT>
   <I_FIL>ERES</I_FIL>
  </INPUT>
  <TABLES>
   <T_ER>
    <item>
        <DATA> HEADER1111111122222222333333344456</DATA>
    </item>
    <item>
         <DATA>778944    D4E2   EA     1234567891 2018-11-060000001000EA 
       0000000000000100001020D04YA30TRE0000000XXXYYY 300{  P 2018-11-05</DATA>
    </item>
    <item>
        <DATA>987654    D4E2   EA     1987654321 2018-11-060000002001EA 
       0000000000000100001020D04YA30UUU0000000XXXLRB 100{  P 2018-11-05</DATA>
    </item>
                .
                .
                .
                .
                .
                .
                .
                .
</T_ER>
</TABLES>
</ZR>

XSLT:

       <?xml version="1.0" encoding="UTF-8"?>
   <xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:fn="http://www.w3.org/2005/xpath-functions" >
    <xsl:output omit-xml-declaration="yes"/>
     <xsl:param name="break" select="'&#xA;'" />

       <xsl:template match="/">
      <xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA"/> 
    <xsl:value-of select="$break" />
    </xsl:template>
   </xsl:stylesheet>

Expected Output:

     HEADER1111111122222222333333344456
        778944    D4E2   EA     1234567891 2018-11-06000000100{EA 
       0000000000000100001020D04YA30TRE0000000XXXYYY 300{  P 2018-11-05
    987654    D4E2   EA     1987654321 2018-11-06000000200AEA 
       0000000000000100001020D04YA30UUU0000000XXXLRB 100{  P 2018-11-05
    .
    .
    .
    .

Upvotes: 1

Views: 729

Answers (2)

Vebbie
Vebbie

Reputation: 1695

Well, using functions string-length, substring and translate for your specifications it can be achieved as:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output omit-xml-declaration="yes" />
<xsl:param name="break" select="'&#xA;'" />

 <xsl:template match="/">
    <xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA" />
    <xsl:value-of select="$break" />

    <xsl:for-each select="ZR/TABLES/T_ER/item[position() != 1]">

        <xsl:variable name="length" select="string-length(substring(DATA,0,46))" />
        <xsl:variable name="tenNumbers" select="substring(DATA, ($length + 1), 10)"/>
        <xsl:variable name="charToReplace" select="translate(substring($tenNumbers, string-length($tenNumbers), 1),'0123456789','{ABCDEFGHI')" />

        <xsl:value-of select="concat(substring(DATA,0,46), substring(DATA, ($length + 1), 9), $charToReplace, substring(DATA,($length+11),(string-length(DATA) + 1)))"/>
        <xsl:value-of select="$break" />
    </xsl:for-each>

 </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Tim C
Tim C

Reputation: 70648

It looks like you just want to replace the 55th character based on your map, so you could do this...

<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA"/> 
<xsl:value-of select="$break" />
<xsl:for-each select="ZR/TABLES/T_ER/item[position() > 1]/DATA">
  <xsl:variable name="char" select="substring('{ABCDEFGHI', number(substring(., 55, 1)) + 1, 1)" />
  <xsl:value-of select="concat(substring(., 1, 54), $char, substring(., 56))" />
  <xsl:value-of select="$break" />
</xsl:for-each>
</xsl:template>

This would work in XSLT 1.0.

An XSLT 2.0 solution could be this...

<xsl:template match="/">
<xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA,
                      ZR/TABLES/T_ER/item[position() > 1]/DATA/concat(substring(., 1, 54), substring('{ABCDEFGHI', number(substring(., 55, 1)) + 1, 1), substring(., 56))" 
              separator="&#xA;" />
</xsl:template>

In XSLT 3.0, you could potentially make use of a map with has the advantage of easily being extended if you wanted to consider two or more characters instead:

<xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:fn="http://www.w3.org/2005/xpath-functions" >

  <xsl:output omit-xml-declaration="yes"/>
  <xsl:param name="break" select="'&#xA;'" />

  <xsl:variable name="chars" as="map(xs:string, xs:string)">
    <xsl:map>
      <xsl:map-entry key="'0'" select="'{'"/>
      <xsl:map-entry key="'1'" select="'A'"/>
      <xsl:map-entry key="'2'" select="'B'"/>
      <xsl:map-entry key="'3'" select="'C'"/>
      <xsl:map-entry key="'4'" select="'D'"/>
      <xsl:map-entry key="'5'" select="'E'"/>
      <xsl:map-entry key="'6'" select="'F'"/>
      <xsl:map-entry key="'7'" select="'G'"/>
      <xsl:map-entry key="'8'" select="'H'"/>
      <xsl:map-entry key="'9'" select="'I'"/>
    </xsl:map>
  </xsl:variable>

  <xsl:template match="/">
    <xsl:value-of select="ZR/TABLES/T_ER/item[1]/DATA,
                          ZR/TABLES/T_ER/item[position() > 1]/DATA/concat(substring(., 1, 54), $chars(substring(., 55, 1)), substring(., 56))" separator="&#xA;" />
  </xsl:template>
</xsl:stylesheet>

There's probably a much nicer way in XSLT 3.0, so hopefully Martin Honnen will be along soon to say....

Upvotes: 2

Related Questions