Search code examples
xmlxsltxslt-2.0xslt-3.0

Update a specific position in a string XSLT


I have an EDI text file which I need to modify using XSLT. I have first transformed the text file into xml which looks like below:

<data>ST^8^347</data>
<data>BAK^00^A^100001396^20240102^^^^20456^a</data>
<data>REF^OQ^5004506</data>

I just need to update the 8th position of the line starting with BAK which is 20456 in above code, to a new value say NEW. Position is determined by delimiter "^"

My xslt code looks like but not working

<data><xsl:value-of select="replace(.,(tokenize(.,'\\^')[9]),'NEW')"/></data>

Expected output is

<data>BAK^00^A^100001396^20240102^^^^NEW^a</data>

Cannot use substring because length of each positions can vary. I can use 8 time substring after but looking for a better approach if possible. Please help.


Solution

  • First you need to have a well-formed XML input:

    XML

    <root>
        <data>ST^8^347</data>
        <data>BAK^00^A^100001396^20240102^^^^20456^a</data>
        <data>REF^OQ^5004506</data>
    </root>
    

    Then you can do:

    XSLT 3.0

    <xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:mode on-no-match="shallow-copy"/>
    
    <xsl:template match="data[starts-with(., 'BAK^')]"> 
        <xsl:variable name="tokens" select="tokenize(., '\^')" />
        <data> 
            <xsl:value-of select="$tokens[position() lt 9], 'NEW' , $tokens[position() gt 9]" separator="^"/>
        </data> 
    </xsl:template> 
    
    </xsl:stylesheet>
    

    to get:

    Result

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
       <data>ST^8^347</data>
       <data>BAK^00^A^100001396^20240102^^^^NEW^a</data>
       <data>REF^OQ^5004506</data>
    </root>
    

    Alternatively you could use:

    <xsl:value-of select="insert-before(remove($tokens, 9), 9, 'NEW')" separator="^"/>
    

    Or:

    <xsl:value-of select="for $i in (1 to count($tokens)) return if ($i=9) then 'NEW' else $tokens[$i]" separator="^"/>