Home > Software design >  three records at once xml mobile pagination on xslt
three records at once xml mobile pagination on xslt

Time:01-17

Need once more a litle bit of help on (re) paginate that already mentioned simple xml table data (XML table columns vertically stacked within rows) but transposed this time as Michael Hor sugested over the above SO's second answer post up, but in addition with displaying three records per (mobile) page. Need this for a mobile pages..
The xml file goes something like this:

<persns> 
 <prsn> 
  <fname>Smith</fname> 
  <lname>Milton</lname> 
  <age>44</age> 
  <addrss>5th summer st, mntb</addrss>
  <city>Portland</city>
 </prsn>
 <prsn> 
  <fname>Ken</fname> 
  <lname>Jackson</lname> 
  <age>37</age> 
  <addrss>19th Penfield ave, brtcl</addrss>
  <city>Kelowna</city>
 </prsn>
 <prsn> 
  <fname>Susan</fname> 
  <lname>Arkland</lname> 
  <age>48</age> 
  <addrss>34th Mansfield st, sgtp</addrss>
  <city>Raleigh</city>
 </prsn>
 <prsn> 
  <fname>George</fname> 
  <lname>Bond</lname> 
  <age>35</age> 
  <addrss>5th drive, mntb</addrss>
  <city>Albany</city>
 </prsn>
 <prsn> 
  <fname>Ron</fname> 
  <lname>Davis</lname> 
  <age>37</age> 
  <addrss>12th Greenfield ave, brtcl</addrss>
  <city>Pheonix</city>
 </prsn>
</persns>

The way displaying is needed is as follows:

|===========|---------------|-------------|------------|  
|   FNAME   |   Smith       |  Ken        |   Susan    |
|===========|---------------|-------------|------------|
|   LNAME   |   Milton      |  Jackson    | Arkland    |
|===========|---------------|-------------|------------|
|    AGE    |     44        |     37      |    48      |
|===========|---------------|-------------|------------|
| ADDRESS   |5th smmr st,mntb9th Pnfeld ave 34th Mansfield st       |===========|---------------|-------------|------------|                                        
|    CITY   |   Portland    |   Kelowna   |  Raleigh   |
|===========|---------------|-------------|------------|
|                  <<   <  1/4  >  >>                  |
|=======================================================
               Fig 1 First Page
|===========|---------------|-------------|------------|  
|   FNAME   |  George       |    Ron      | Marie-Ann  |
|===========|---------------|-------------|------------|
|   LNAME   |    Bond       |    Davis    | Spencer    |
|===========|---------------|-------------|------------|
|    AGE    |      35       |    37       |    48      |
|===========|---------------|-------------|------------|
| ADDRESS   |5th drive, mntb|12th Greenfld ave 273 Simpson square                
|===========|---------------|-------------|------------|                                        
|    CITY   |   Albany      |    Pheonix  |  Oklahoma  |
|===========|---------------|-------------|------------|
|                  <<   <  2/4  >  >>                  |
|=======================================================
            Fig 2 Second Page

Exactly as Michael Hor suggested through that previous post's answer. And that stylesheet is somehow as follows:

<xsl:param name="frame" select="3"/>
<xsl:template match="persns">
<xsl:apply-templates select="prsn[position() mod $frame=1]">
<xsl:with-param name="pags" select="ceiling(count(prsn) div$frame)"/>    
</xsl:apply-templates>
</xsl:template>

<xsl:template match="/prsn">
<xsl:variable name="rec" select="prsn"/>
 <table border="1">
  <xsl:for-each select="prsn[1]/*">
<xsl:variable name="pag" select="position()"/>
<tr><th><xsl:value-of select="name()"/></th>
 <xsl:for-each select="$rec">
  <td><xsl:value-of select="*[$pag]"/> </td>
 </xsl:for-each>
 </tr>
</xsl:for-each>
</table>
 </xsl:template>

As one can easily notice the second template - just by itself - would correctly displays All the xml records. And it does it exactly the way I wanted to, but without pagination. If I actually insert the first template (on the other hand) where is xsl:apply-templates declaration and "with param" stuff everything gets "mixed up"; as first template - by itself - displays that set of 3 records (or something) with no formatting and ignoring the second template which is suppose to display records in a formated manner. Don't know why those two templates are somehow "mutually exclusive"
After that it comes the pagination section area, and a couple of small js functions bound over those <a href links. All these could be found here: one record at a time xml pagination on xslt This would be it for now. I really struggled for weeks for properly display all these.
Thank you guys în advance.

CodePudding user response:

I suppose the element names are known; I also think that most XSLT 2 processors (e.g. Saxon) these days in its current versions (10, 11, 12) support XSLT 3 so you could use XSLT 3 as

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">
  
  <xsl:param name="items-per-page" as="xs:integer" select="3"/>
  
  <xsl:template match="persns">
    <xsl:variable name="data-arrays" as="array(map(*)*)*">
          <xsl:for-each-group select="prsn" group-adjacent="(position() - 1) idiv $items-per-page">
            <xsl:sequence select="array { current-group() ! map { 'fname' : data(fname), 'lname' : data(lname), 'age' : data(age), 'address' : data((addrss, ciyt)) }}"/>
          </xsl:for-each-group>
    </xsl:variable>
    <xsl:for-each select="$data-arrays">
      <table  style="display: {if (position() eq 1) then '''''' else 'none'}">
        <tbody>
          <xsl:variable name="data-maps" select="?*"/>
          <tr>
            <th>fname</th>
            <xsl:for-each select="$data-maps?fname">
              <td>{.}</td>
            </xsl:for-each>
          </tr>
          <tr>
            <th>lname</th>
            <xsl:for-each select="$data-maps?lname">
              <td>{.}</td>
            </xsl:for-each>
          </tr>
          <tr>
            <th>age</th>
            <xsl:for-each select="$data-maps?age">
              <td>{.}</td>
            </xsl:for-each>
          </tr>
          <tr>
            <th>address</th>
            <xsl:for-each select="$data-maps?address">
              <td>{.}</td>
            </xsl:for-each>
          </tr>
        </tbody>
      </table>      
    </xsl:for-each>
    <nav>
      <input type="button" value="&lt; previous page" onclick="previousPage()"/>
      <input type="button" value="> next page" onclick="nextPage()"/>
    </nav>
  </xsl:template>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="html" indent="yes" html-version="5"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>.NET XSLT Fiddle Example</title>
        <script xsl:expand-text="no">
        var currentPageIndex = 0;
        var pages;
        
        function nextPage() {
          pages[currentPageIndex].style.display = 'none';
          currentPageIndex  ;
          if (currentPageIndex > lastPageIndex)
            currentPageIndex = 0;
          pages[currentPageIndex].style.display = '';
        }
        
        function previousPage() {
          pages[currentPageIndex].style.display = 'none';
          currentPageIndex--;
          if (currentPageIndex &lt; 0)
            currentPageIndex = lastPageIndex;
          pages[currentPageIndex].style.display = '';
        }
        
        var lastPageIndex = -1;
        
        document.addEventListener('DOMContentLoaded', 
          function(evt) {
            pages = document.getElementsByClassName('page');
            lastPageIndex = pages.length - 1;
          },
          false
        );
        </script>
        <style xsl:expand-text="no">
          table, tr, td, th { border: 1px solid black; }
        </style>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>
  
</xsl:stylesheet>

I haven't disabled the previous/next page buttons, instead let next page if showing the last one go to page 1 and previous page if showing the first page go to the last page.

Here is a

fname {.}
lname {.}
age {.}
address {.}
.NET XSLT Fiddle Example <script xsl:expand-text="no"> var currentPageIndex = 0; var pages; function nextPage() { pages[currentPageIndex].style.display = 'none'; currentPageIndex++; if (currentPageIndex > lastPageIndex) currentPageIndex = 0; pages[currentPageIndex].style.display = ''; } function previousPage() { pages[currentPageIndex].style.display = 'none'; currentPageIndex--; if (currentPageIndex < 0) currentPageIndex = lastPageIndex; pages[currentPageIndex].style.display = ''; } var lastPageIndex = -1; document.addEventListener('DOMContentLoaded', function(evt) { pages = document.getElementsByClassName('page'); lastPageIndex = pages.length - 1; }, false ); </script> <style xsl:expand-text="no"> table, tr, td, th { border: 1px solid black; } </style> <body> &input= Smith Milton 44 5th summer st, mntb Portland Ken Jackson 37 19th Penfield ave, brtcl Kelowna Susan Arkland 48 34th Mansfield st, sgtp Raleigh George Bond 35 5th drive, mntb Albany Ron Davis 37 12th Greenfield ave, brtcl Pheonix &input-type=XML" rel="nofollow noreferrer">link to the SaxonJS, browser-side XSLT fiddle having the sample code.

  • Related