xsltxslt-1.0xslt-2.0xslt-3.0

XSLT Split into separate segments based on key field value


i am trying to write XSLT mapping to create separate Instruction segment based on sub segment Instructiontext, whenever there is key word called /NEW LINE/ is present in the InstructionText segment. I have written a code but its giving error, Please help me on this..

i attached sample input and output as below. Please check.

Input:

<?xml version="1.0" encoding="UTF-8"?>
<TIM>
    <SBDH>
        <FIELD1>132</FIELD1>
    </SBDH>
    <TI>
        
        <TIC>           
            <Instruction>
                <InstructionText languageCode="EN">20</InstructionText>
            </Instruction>
            <Instruction>
                <InstructionText languageCode="EN">234</InstructionText>
            </Instruction>
            <Instruction>
                <InstructionText languageCode="EN">456 /NEW LINE/ 789 /NEW LINE/ 910/NEW LINE/</InstructionText>
            </Instruction>
            
        </TIC>
    </TI>
</TIM>

** Desired Output:**

<?xml version="1.0" encoding="UTF-8"?>
<TIM>
    <SBDH>
        <FIELD1>132</FIELD1>
    </SBDH>
    <TI>
        <TIC>
            <Instruction>
                <InstructionText languageCode="EN">20</InstructionText>
            </Instruction>
            <Instruction>
                <InstructionText languageCode="EN">234</InstructionText>
            </Instruction>
            <Instruction>
                <InstructionText languageCode="EN">456</InstructionText>
            </Instruction>
            <Instruction>
                <InstructionText languageCode="EN">789</InstructionText>
            </Instruction>
            <Instruction>
                <InstructionText languageCode="EN">910</InstructionText>
            </Instruction>
        </TIC>
    </TI>
</TIM>

** XSLT I used is below:**

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
    <xsl:template match="/">
       
            <xsl:for-each select="//InstructionText">
            
                <xsl:for-each select="tokenize(string(InstructionText), '/NEW LINE/')">
                    <InstructionText>
                        <InstructionText><xsl:value-of select="."/></InstructionText>
                      
                     </InstructionText>
                </xsl:for-each>
            </xsl:for-each>
      
    </xsl:template>
</xsl:stylesheet>   

Please assist here.


Solution

  • If your processor supports XSLT 3.0, you should be able to do something like:

    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:mode on-no-match="shallow-copy"/>
    
    <xsl:template match="Instruction"> 
          <xsl:apply-templates/>
    </xsl:template>
    
    <xsl:template match="InstructionText">
        <xsl:variable name="languageCode" select="@languageCode" />       
        <xsl:for-each select="tokenize(., '/NEW LINE/')[normalize-space(.)]">
            <Instruction>
                <InstructionText languageCode="{$languageCode}">
                    <xsl:value-of select="normalize-space(.)"/>
                </InstructionText>
            </Instruction>
        </xsl:for-each>
    </xsl:template>
    
    </xsl:stylesheet>  
    

    You can see it working here.