Sunday, November 11, 2018

Retrieving subset of xml using xslt mediator in WSO2 ESB 5.0.0

This article explain a solution to a scenario, where our back end service is not supporting a pagination and responds with a large xml and our client expects an API which need to support pagination.

The flow diagram below summarizes the task we are going to achieve.

The API I have created for this sample as below:

<api xmlns="http://ws.apache.org/ns/synapse" name="PaginationAPI" context="/listStudents">
   <resource methods="GET" uri-template="/getPaginatedStudentsList?start={start}&amp;count={count}" protocol="http">
      <inSequence>
         <log level="custom">
            <property name="STATUS" value="PaginationAPI Invoked..."/>
            <property name="start" expression="$ctx:query.param.start"/>
            <property name="count" expression="$ctx:query.param.count"/>
         </log>
         <script language="js">var count = parseInt(mc.getProperty('query.param.count'));                var start = parseInt(mc.getProperty('query.param.start'));        var startIndex = parseInt(start);       var endIndex = parseInt(start) + parseInt(count) + 1;         mc.setProperty('startIndex', startIndex);        mc.setProperty('endIndex', endIndex);</script>
         <call>
            <endpoint>
               <http method="GET" uri-template="http://www.mocky.io/v2/5be818f7300000750058c312"/>
            </endpoint>
         </call>
         <log level="full" description="before xslt transformation"/>
         <xslt key="gov:/pagination-test.xslt">
            <property name="startIndex" expression="$ctx:startIndex"/>
            <property name="endIndex" expression="$ctx:endIndex"/>
         </xslt>
         <respond/>
      </inSequence>
      <outSequence/>
      <faultSequence/>
   </resource>
</api>
                        

The back end service has been created in mocky.io and the sample data response from it will be as below:

<soapenv:Envelope
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
 <soapenv:Header/>
 <soapenv:Body>
  <students>
   <school>St.Michael's College, Batticaloa</school>
   <address>Batticaloa, Srilanka</address>
   <student>
    <recno>1</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>2</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1
   </address>
    <age>27</age>
   </student>
   <student>
    <recno>3</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>4</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>5</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>6</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>7</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>8</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>9</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>10</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>11</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
   <student>
    <recno>12</recno>
    <name>NTest1</name>
    <surname>STest1</surname>
    <address>ATest1</address>
    <age>27</age>
   </student>
  </students>
 </soapenv:Body>
</soapenv:Envelope>

Then the XSLT will be as below:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
 <xsl:param name="startIndex"></xsl:param>
 <xsl:param name="endIndex"></xsl:param>
 <xsl:template match="/">
  <students>
   <xsl:apply-templates select="//students/student[position() > $startIndex and position() &lt; $endIndex]"/>
  </students>
 </xsl:template>
 <xsl:template match="//students/student[position() > $startIndex and position() &lt; $endIndex]">
  <xsl:copy-of select="."/>
 </xsl:template>
</xsl:stylesheet>

Below are the test results:
1) When calling the API with URL: http://172.17.0.1:8280/listStudents/getPaginatedStudentsList?start=0&count=20
<students>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>1</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>2</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1
   </address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>3</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>4</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>5</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>6</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>7</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>8</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>9</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>10</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>11</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>12</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
</students>

2) When calling the API with URL: http://172.17.0.1:8280/listStudents/getPaginatedStudentsList?start=5&count=3
<students>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>6</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>7</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
    <student xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
        <recno>8</recno>
        <name>NTest1</name>
        <surname>STest1</surname>
        <address>ATest1</address>
        <age>27</age>
    </student>
</students>

That's it... and hope this helps someone implementing a pagination scenario.