Search code examples
xmlxslt

xml paged transposed transaction sorted data display as html table in xslt2


Got same old (unordered) xml data file (7 "records" this time) ...

<trnsctns>  
 <trnsctn date="19/01/01"><OB>180</OB><amnt/></trnsctn>
 <trnsctn date="19/03/03"><OB/><amnt>33</amnt></trnsctn>
 <trnsctn date="19/02/02"><OB/><amnt>21</amnt></trnsctn>
 <trnsctn date="19/05/05"><OB/><amnt>29</amnt></trnsctn>
 <trnsctn date="19/04/04"><OB/><amnt>44</amnt></trnsctn>
 <trnsctn date="19/06/08"><OB/><amnt>17</amnt></trnsctn> 
<trnsctn date="19/07/03"><OB/><amnt>17</amnt></trnsctn>
</trnsctns>

and through Martin Honnen's xslt2/xslt3 transform stylesheet (xml transposed transaction sorted data display as html table in xslt2) was able to bulk sort display ALL that xml data file.

Very good think and I thank him again for this valuable solution.

On one hand all this (mentioned) data is supposed to be displayed over some mobile device (mobile phone) and on the other hand all that data stuff grows so one need a pagination mechanism in order display it. Really sorry for keep coming with this, but really think that's the last time I'd need this sort of requirment.

Anyway this paged and sorted xml data transformed (xslt2/xslt3) display I need it exactly as showcased through the following fiddle:

https://jsfiddle.net/2twnxz97/7/

Meaning that over that previously xslt transform one should "only" add that pagination system. This would be it.

Looking forward on this pagination technique which was unable to figure out how could be done. Thank you all in advance


Solution

  • You can use your script in the result document of the XSLT, e.g. from the previous answer you would add a template creating the HTML and including the script with e.g.

    <xsl:template match="/">
      <html>
        <head xsl:expand-text="no">
          <title>Example pagination</title>
          <script><![CDATA[
    onload=function()  
        {
        colsPerPage=3 
        currentPage=1
        table=document.getElementById('myTable')  
    
        totalCols = table.rows[0].cells.length - 1 // Exclude the header row
        // calculate the total number of pages
      totalPages = Math.ceil(totalCols/colsPerPage)
    
        // Initialize the pagination container
        paginationContainer=document.getElementById('pagination-container')
    
        // Initial display of the first page
      displayPage(1)
     }
    
    // Function to display the specified page
    function displayPage(pageNumber)
    {
     startIndex=(pageNumber-1)*colsPerPage + 1
     endIndex=Math.min(startIndex+colsPerPage-1,totalCols)
    
     for(i=0;i<table.rows.length;i++)
      for(j=1;j<=totalCols;j++)
       table.rows[i].cells[j].style.display=(j>=startIndex && j <= endIndex)?'':'none'
       
     currentPage=pageNumber
     updatePagination()
    }
    
    function updatePagination() // update pagination controls
    {
     const paginationLinks=generatePaginationLinks()
     paginationContainer.innerHTML=''
     paginationContainer.appendChild(paginationLinks)
    }
    
    function generatePaginationLinks()
    {
     fragment = document.createDocumentFragment()
     createLink = function(text,clickHandler)
            {
             link=document.createElement('a')
             link.href = '#'
             link.textContent = text
             link.addEventListener('click',function(event)
                {
                 event.preventDefault()
             clickHandler()
                })
             return link
             }
    
     first = createLink('|<First',function()
                {
                 displayPage(1)
                })
     fragment.appendChild(first)
     previous = createLink('<Previous',function()
                 {
                  if(currentPage>1)
                   displayPage(currentPage-1)
                 })
     fragment.appendChild(previous)
    
     pageInfo = document.createElement('span')
     pageInfo.id = 'pgnInf' 
     pageInfo.textContent = `${currentPage}/${totalPages}`
     fragment.appendChild(pageInfo)
    
     next = createLink('Next>',function()
                 {
                  if(currentPage<totalPages)
                   displayPage(currentPage + 1)
                 })
     fragment.appendChild(next)
    
     last=createLink('Last>|',function()
                  {
            displayPage(totalPages)
                  })
     fragment.appendChild(last)
     return fragment
    }        
          ]]></script>
        </head>
        <body>
          <xsl:apply-templates/>
        </body>
      </html>
    </xsl:template>
    

    then adjust the template outputting the table to ensure it has the id attribute and it also adds that span for your pagination/navigation:

    <xsl:template match="/trnsctns">
        <xsl:variable name="data-table">
          <tr>
              <th>date</th>
              <th>ob</th>
              <th>amnt</th>
              <th>cb</th>
          </tr>
            <xsl:call-template name="process">
                <xsl:with-param name="transactions" as="element()*" select="trnsctn => sort((), function($t) { replace($t/@date, '([0-9]{2})/([0-9]{2})/([0-9]{2})', '$3$2$1')})"/>
            </xsl:call-template>          
        </xsl:variable>
        
        <xsl:variable name="swapped-table" select="mf:swap-table($data-table/tr)"/>
    
        <table id="myTable" border="1">
          <tr>
            <th>crrntNmbr</th>
            <xsl:for-each select="1 to count($swapped-table[1]/*) - 1">
              <td>{position()}</td>
            </xsl:for-each>
          </tr>
          <xsl:sequence select="$swapped-table"/>
        </table>
        
        <span id="pagination-container"></span>
    
    </xsl:template>
    

    You only need to add your CSS for the layout of the table and the navigation/pagination area and you should get the result you want.