Showing posts with label XSLT. Show all posts
Showing posts with label XSLT. Show all posts
Sunday, August 16, 2026

XSLT Conditional Logic: if, choose, when and otherwise

In XSLT (Extensible Stylesheet Language Transformations), we often need to produce different output based on conditions. XSLT gives us two main instructions for this. The xsl:if instruction and the xsl:choose instruction. In XSLT 2.0 or later, we also have a shorter inline syntax. I thought of writing a blog post so others can easily find examples as well.

xsl:if Instruction

Saturday, July 25, 2026

XSLT Sorting with xsl:sort

 Sorting is a very common requirement in XSLT transformations. XSLT gives us the xsl:sort instruction for this. It works inside xsl:for-each and inside xsl:apply-templates. While working on integration scenarios, I have used almost every option of xsl:sort. I thought of writing a blog post so others can easily find examples as well.

Basic Sorting

The xsl:sort instruction must be the first child of xsl:for-each. The select attribute defines the sort key.

<?xml version="1.0" encoding="UTF-8"?>
<employees>
    <employee>
        <name>Nimal</name>
        <salary>85000</salary>
        <department>Finance</department>
    </employee>
    <employee>
        <name>Amara</name>
        <salary>92000</salary>
        <department>Engineering</department>
    </employee>
    <employee>
        <name>Kasun</name>
        <salary>78000</salary>
        <department>Engineering</department>
    </employee>
</employees>

Sort by name:

Wednesday, July 03, 2024

XSLT Date and Time Manipulation

In XSLT (Extensible Stylesheet Language Transformations) 2.0 or later, we can perform several date and time manipulation processes. I thought of writing a blog post so others can easily find examples as well.

Basic Date & Time XSLT Functions: 

current-date() - Returns the current date of the server that XSLT runs

current-time() - Returns the current time of the server that XSLT runs

current-dateTime() - Returns the current date and time of the server that XSLT runs

implicit-timezone() - Returns the implicit time zone of the server that XSLT runs

Sunday, December 01, 2019

Compare Two XML Elements and Filter using WSO2 MI


Think about an integration scenario, where you are getting a list of data from a service endpoint(Data 1) and you want to exclude or match this response against the data returned by another service endpoint(Data 2).

In such a situation, first, you need to have a unique attribute in both data set to exclude or match elements. So in my use case, list of data and matching content is as below


<CodeLists>
 <CodeList>
        <Id>O</Id>
        <Name>Open</Name>
    </CodeList>
    <CodeList>
        <Id>C</Id>
        <Name>Cancelled</Name>
    </CodeList>
    <CodeList>
        <Id>X</Id>
        <Name>Denied</Name>
    </CodeList>
 <CodeList>
        <Id>P</Id>
        <Name>Pending</Name>
    </CodeList>
 <CodeList>
        <Id>D</Id>
        <Name>Duplicate</Name>
    </CodeList>
</CodeLists>
Data 1


<CodeLists>
    <CodeList>
        <Id>O</Id>
        <Name>Open</Name>
    </CodeList>
    <CodeList>
        <Id>P</Id>
        <Name>Pending</Name>
    </CodeList>
</CodeLists>
Data 2


So here I am going to use WSO2 Enterprise Integrator and its XSLT mediator to filter the results. First I am joining all the elements that need to be hidden into a single Synapse property.


<property name="elementsToBeHide" expression="string-join(//CodeLists/CodeList/Id, ',')" scope="default" type="STRING"/>


Then I am calling my XSLT with elementsToBeHide as a parameter.


<xslt key="conf:/xslts/xslt_FilterResults.xslt">
    <property name="elementsToBeHide" expression="$ctx:elementsToBeHide"/>
</xslt>

My XSLT file is stored in the registry. However, if you are using a Micro Integrator profile, you can add this XSLT as a local entry.  Inside my XSLT document, I am looping all code list elements and check whether each ID exists in 'elementsToBeHide' parameter. You can use the same XSLT Choose Condition to filter data based on matching or not matching scenarios. In my example, if ID is not matching to the current ID, it will be added to Code element.


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:sy="http://ws.apache.org/ns/synapse" xmlns:fn="http://www.w3.org/2005/xpath-functions"
 xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
 <xsl:strip-space elements="*" />
 
 <xsl:param name="elementsToBeHide" />

 <xsl:template match="/CodeLists">
  <CodeLists>
   <CodeList>
    <xsl:for-each select="CodeList">
                     <xsl:choose>
             <xsl:when test="matches($elementsToBeHide,Id)">
       <!-- match senarios -->
             </xsl:when>
             <xsl:otherwise>
       <!-- not matching -->
              <Code>
       <Name><xsl:value-of select="Name"/></Name>
       <Id><xsl:value-of select="Id"/></Id>
        </Code>
             </xsl:otherwise>
         </xsl:choose>
    </xsl:for-each>
   </CodeList>
  </CodeLists>
 </xsl:template> 
</xsl:stylesheet>


The output of the XSLT transformation is as below and it only includes elements which are not matching to the filtering data set.


<CodeLists>
 <CodeList>
  <Code>
   <Id>C</Id>
   <Name>Cancelled</Name>
  </Code>
  <Code>
   <Id>X</Id>
   <Name>Denied</Name>
  </Code>
  <Code>
   <Id>D</Id>
   <Name>Duplicate</Name>
  </Code>
 </CodeList>
</CodeLists>
Friday, January 04, 2019

XSLT - Modify Date and DateTime value

If you want to perform date and time related opertions with XSLT 'date' or 'dateTime' values, you can use 'xs:yearMonthDuration' or 'xs:dayTimeDuration' function to achieve this. You can add or reduce years, months, date, hours or even minutes through those functions.


 xs:yearMonthDuration

For this function input value is year month duration and it should be passed in ISO_8601 format

n- the [n] is replaced by the value for each of the date and time elements
P - The duration designator(for period).
nY- the number of years.
nM- the number of months.

ex: xs:yearMonthDuration('P1Y2M') - 1 Year and 2 Months
ex: xs:yearMonthDuration('-P1Y2M') - Negative 1 Year and 2 Months

xs:dayTimeDuration

For this function input value is day time duration and it also needs to be passed in ISO_8601 format

n- the [n] is replaced by the value for each of the date and time elements
P - The duration designator(for period).
nD- the number of days.
T- The date and time separator.
nH- the number of hours.
nM- the number of minutes.
nS - the number of seconds.

ex: xs:dayTimeDuration('P3D') - 3 Days
ex: xs:dayTimeDuration('-P3D') - Negative 3 days
ex: xs:dayTimeDuration('P6DT50H80S') - 6 days, 50 hours, and 80 seconds


Example XSLT :

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" >

  <xsl:output method="text"/>

  <xsl:variable name="dT" as="xs:dateTime"   select="xs:dateTime('2016-02-29T00:00:01')"/>
  <xsl:variable name="d" as="xs:date" select="xs:date('2016-02-29')"/>

  <xsl:template match="/">
       <xsl:text>Add 1 Year and 2 Months : </xsl:text> <xsl:value-of select="($d+ xs:yearMonthDuration('P1Y2M'))"/>
       <xsl:text>&#xA;Negative 1 Year and 2 Month : </xsl:text> <xsl:value-of select="($d+ xs:yearMonthDuration('-P1Y2M'))"/>

       <xsl:text>&#xA;Add 3 Days : </xsl:text> <xsl:value-of select="($dT+ xs:dayTimeDuration('P3D'))"/>
       <xsl:text>&#xA;Negative 3 days : </xsl:text> <xsl:value-of select="($dT+xs:dayTimeDuration('-P3D'))"/>
       <xsl:text>&#xA;Add 6 days, 50 hours, and 80 seconds : </xsl:text> <xsl:value-of select="($dT+ xs:dayTimeDuration('P6DT50H80S'))"/>
  </xsl:template>
</xsl:stylesheet>


More on XSLT:
Friday, February 20, 2015

Remove duplicate XML elements using XSLT

Today I faced an issue where I am receiving a XML message with duplicate elements. So I wanted to remove those duplicate elements using some condition . For that I came up with a XSLT which does that.

My XML input:

<OurGuestsCollection xmlns="http://ws.wso2.org/dataservice">
    <OurGuests>
        <id>2</id>
        <firstname>Sample</firstname>
        <lastname>Sample</lastname>
        <email>One</email>
        <reg_date>2015-02-18T13:59:43.000+05:30</reg_date>
    </OurGuests>
    <OurGuests>
        <id>3</id>
        <firstname>Sample1</firstname>
        <lastname>Sample1</lastname>
        <email>One</email>
        <reg_date>2015-02-18T14:13:18.000+05:30</reg_date>
    </OurGuests>
    <OurGuests>
        <id>4</id>
        <firstname>Sample1</firstname>
        <lastname>Sample1</lastname>
        <email>One1</email>
        <reg_date>2015-02-18T14:16:21.000+05:30</reg_date>
    </OurGuests>
</OurGuestsCollection>

XSLT:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="m0:OurGuests"
        xmlns:m0="http://ws.wso2.org/dataservice">
        <xsl:if test="not(following::m0:OurGuests[m0:firstname=current()/m0:firstname])">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

XML Output :

<OurGuestsCollection xmlns="http://ws.wso2.org/dataservice">
    <OurGuests>
        <id>2</id>
        <firstname>Sample</firstname>
        <lastname>Sample</lastname>
        <email>One</email>
        <reg_date>2015-02-18T13:59:43.000+05:30</reg_date>
    </OurGuests>

    <OurGuests>
        <id>4</id>
        <firstname>Sample1</firstname>
        <lastname>Sample1</lastname>
        <email>One1</email>
        <reg_date>2015-02-18T14:16:21.000+05:30</reg_date>
    </OurGuests>
</OurGuestsCollection>

View Counts

Followers