Search code examples
xmlxpathxslt-2.0

xml nodes limit display


Got the following xml file

<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>
 <prsn> 
  <fname>Marie-Ann</fname> 
  <lname>Spencer</lname> 
  <age>48</age> 
  <addrss>273 Simpson square</addrss>
  <city>Oklahoma</city>
 </prsn>
<prsn> 
  <fname>David</fname> 
  <lname>Rhonson</lname> 
  <age>45</age> 
  <addrss>255 Lakeland Terrace, mi</addrss>
  <city>Livonia</city>
 </prsn>
</persns>

and, again for paging purposes need the children nodes display limited at just 3 items per page. And for this one has to have somehow two (or perhaps one..) templates. First one, like this

 <xsl:variable name="frme" select="3" />
 <xsl:template match ="persns">
<xsl:apply-templates select="prsn[position()mod$frme=1]"/>
</xsl:template>

and the second, something like this (which's not working..)

<xsl:template match="/prsn">
<!-- do some html table formatting and display those particular prsn's name, age etc -->
</xsl:template>

Because only the first template is actually fired and sequentially displays (almost correctly) all of the 8 or 9 prsn node details, the second template is simply ignored (which is right). Question is how one is supposed format displaying - at one time - that limited number of persons children nodes along with theirs sub-characteristics: age, address, city etc. Already asked this kind of question, but that working solution ain't quite working for me through that old xslt 2 frameless processor. I strongly need this sort of solution till I switch over Saxon processor and setting over that previously mentioned answer. Thank you very much in advance.


Solution

  • Although with some significant delay I'll somehow show the solution of this stacked data (paged) displaying as initially rised up here more than several months ago. Maybe some people would still be interested on how this could be done; especially this kind of "complete" solution which one would hardly ever found ... And really I know what I'm talking about ! Anyway .. here's the another slighlty previously modified (simplified) xml file :

    <persns> 
     <prsn> 
      <fname>Smith</fname> 
      <lname>Milton</lname> 
      <age>44</age> 
      <addrss>
       <strt>5th summer st, mntb</strt>
       <zipcd>78455509</zipcd>  
       <city>Portland</city>
      </addrss> 
     </prsn>
     <prsn> 
      <fname>Ken</fname> 
      <lname>Jackson</lname> 
      <age>37</age> 
      <addrss>
       <strt>19th Penfield ave, brtcl</strt>
       <zipcd>872356223</zipcd>    
       <city>Kelowna</city>
      </addrss> 
     </prsn>
     <prsn> 
      <fname>Susan</fname> 
      <lname>Arkland</lname> 
      <age>48</age> 
      <addrss>
       <strt>34th Mansfield st, sgtp</strt> 
       <zipcd>341289654</zipcd>  
       <city>Raleigh</city>
      </addrss> 
     </prsn>
     . . . . .
     <prsn> 
      <fname>David</fname> 
      <lname>Rhonson</lname> 
      <age>45</age> 
      <addrss>
       <strt>255 Lakeland Terrace, mi</strt>
       <zipcd>6000432217</zipcd>   
       <city>Livonia</city>
      </addrss> 
     </prsn>
     <prsn> 
      <fname>Buddy</fname> 
      <lname>Clark</lname> 
      <age>53</age> 
      <addrss>
       <strt>Lkeshore Lane Zion, il</strt>
       <zipcd>45230976521</zipcd>   
       <city>Oneonta</city>
      </addrss> 
    </prsn>
     <prsn> 
      <fname>Peggy</fname> 
      <lname>Johnson</lname> 
      <age>42</age> 
      <addrss>
       <strt>w.Devon ave. Monroe Township, nj</strt>
       <zipcd>3456872112</zipcd>
       <city>New Jersey</city>
      </addrss> 
     </prsn>
     <prsn> 
      <fname>Julie</fname> 
      <lname>Nelson</lname> 
      <age>35</age> 
      <addrss>
       <strt>Wagon st.Springfield,pa</strt>
       <zipcd>76245127832</zipcd>   
       <city>Pennsylvania</city>
      </addrss> 
     </prsn>
    </persns>
    

    and through the xslt transformation I'll further present, one would like to display it (and also function) like as it showcased through the following pictures:

    p1 p2 p3 p4 p5

    So, the xslt transform goes like this:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" html-version="5"/>
    <meta charset="UTF-8" name="viewport" content="width=device-width, height=device-height, initial-scale=1.1"/>
    <xsl:variable name="url" select="base-uri()"/>
    <xsl:param name="pag">
    <xsl:choose>
     <xsl:when test="$url = substring-before(concat($url,'?'),'?')">
    <xsl:value-of select="1"/>
     </xsl:when>
     <xsl:otherwise>
     <xsl:analyze-string select="$url" regex="[\?&amp;]([^=]+)=([^&amp;]+)">
      <xsl:matching-substring>
    <xsl:value-of select="regex-group(2)"/>
     </xsl:matching-substring>
    </xsl:analyze-string>
     </xsl:otherwise>
    </xsl:choose>
    </xsl:param>
    
    <xsl:variable name="windw" select="3"/>
    
    <xsl:template match="persns">
     <xsl:variable name="rcrds" select="count(persns/prsn)"/>
     <xsl:variable name="pags" select="ceiling(count(prsn) div $windw)"/> 
     <xsl:variable name="start" select="($pag - 1)*$windw + 1"/>
     <xsl:variable name="lmt" select="prsn[position() ge $start and position() &lt; $start + $windw]"/>
     
     <table border="1" style="border-collapse:collapse"> 
      <xsl:for-each select="$lmt[1]/*[not(self::addrss)]">
       <xsl:variable name="i" select="position()"/>
       <tr><th><xsl:value-of select="name()"/></th> 
        <xsl:for-each select="$lmt">
         <td>
          <xsl:value-of select="*[$i]"/> 
          <xsl:if test="$i mod 3=1">
           <xsl:text> [</xsl:text>
           <xsl:element name="span">
           <xsl:text>+</xsl:text>
            <xsl:attribute name="id">
            <xsl:choose>
             <xsl:when test="position()mod3=1">
              <xsl:text>cp1_rcrd01</xsl:text>
             </xsl:when>
             <xsl:when test="position()mod2=0">
              <xsl:text>cp2_rcrd01</xsl:text>
             </xsl:when>
             <xsl:when test="position()mod3=0">
              <xsl:text>cp3_rcrd01</xsl:text>
             </xsl:when>
            </xsl:choose>
           </xsl:attribute>
         <xsl:attribute name="class">
        <xsl:text>cSsmbl_01</xsl:text>
      </xsl:attribute>
      <xsl:attribute name="onclick">fnct(this,'cpz1','cpz2','cpz3')</xsl:attribute>
      </xsl:element>
      <xsl:text>]</xsl:text>
      </xsl:if>
      </td>
      <th>
     <xsl:attribute name="class">
      <xsl:choose>
       <xsl:when test="position()mod3=1">
         <xsl:text>cpz1</xsl:text>
       </xsl:when>
       <xsl:when test="position()mod2=0">
         <xsl:text>cpz2</xsl:text>
       </xsl:when>
       <xsl:when test="position()mod3=0">
         <xsl:text>cpz3</xsl:text>
       </xsl:when>
      </xsl:choose>
     </xsl:attribute>
     <xsl:value-of select="addrss/*[$i]/name()"/>
     </th>
     <td>
      <xsl:attribute name="class">
      <xsl:choose>
       <xsl:when test="position()mod3=1">
        <xsl:text>cpz1</xsl:text>
       </xsl:when>
       <xsl:when test="position()mod2=0">
        <xsl:text>cpz2</xsl:text>
       </xsl:when>
       <xsl:when test="position()mod3=0">
        <xsl:text>cpz3</xsl:text>
       </xsl:when>
      </xsl:choose>
     </xsl:attribute>
     <xsl:value-of select="addrss/*[$i]"/>
     </td>
     </xsl:for-each>
     </tr>
     </xsl:for-each>
    </table>
    <!-- First/Prev link for pagination -->
      <xsl:choose>
       <xsl:when test="number($pag) ge 1">
       &#160;<a id="pida" href="index.html?pag={number($pags)-number($pags)+1}" onclick="">&lt;&lt;First</a>
       &#160;<a id="pida" href="index.html?pag={number($pag)-1}" onclick="">&lt;Prev</a>
       </xsl:when>
       <xsl:otherwise>
      <!-- display smthing else -->
       &#160;<a><xsl:attribute name="href">index.html?pag=<xsl:value-of select="number($pag)"/></xsl:attribute>&lt;&lt;Prev</a>
       </xsl:otherwise>
     </xsl:choose> 
    
     <xsl:if test="$pags gt 1">
    &#160;<b><xsl:value-of select="number($pag)"/>&#160;/&#160;<xsl:value-of select="number($pags)"/></b>&#160;
     </xsl:if>
          
     <!-- Next/Last link for pagination -->
      <xsl:choose>
       <xsl:when test="number($pag) lt number($pags)">
       &#160;<a id="nida" href="index.html?pag={number($pag)+1}">Next&gt;</a>&#160;
          <a id="nida" href="index.html?pag={number($pags)}" onclick="">Last&gt;&gt;</a>
       </xsl:when>
       <xsl:otherwise>
        <!-- display smthing else -->
       </xsl:otherwise>
      </xsl:choose>
     <!-- end of pgntn sect -->
    </xsl:template>
    </xsl:stylesheet>
    

    But, wait, there are a small .js script which actually controls page transitions. So this one is as follows:

    function fnct(spn,cpz1,cpz2,cpz3)
    {
     setCcmpzt_01=document.getElementsByClassName(cpz1) /* 1'st hdr-col pair */
     setCcmpzt_02=document.getElementsByClassName(cpz2) /* 2'nd hdr-col pair */
     setCcmpzt_03=document.getElementsByClassName(cpz3) /* 3'rd hdr-col pair */
     tblAtbCcpz=[setCcmpzt_01,setCcmpzt_02,setCcmpzt_03]
     if(spn.innerHTML=='+')
      {
       spn.innerHTML='-'
       switch(spn.id)
       {
        case 'cp1_rcrd01': 
         for(j=0;j<tblAtbCcpz[0].length;j++)
          tblAtbCcpz[0][j].style.display="table-cell"
         break
        case 'cp2_rcrd01':
         for(j=0;j<tblAtbCcpz[1].length;j++)
          tblAtbCcpz[1][j].style.display="table-cell"
         break
        case 'cp3_rcrd01':
         for(j=0;j<tblAtbCcpz[2].length;j++)
          tblAtbCcpz[2][j].style.display="table-cell"
         break
        }
      }
      else
      {
       spn.innerHTML='+'
       switch(spn.id)
       {
        case 'cp1_rcrd01':
         for(j=0;j<tblAtbCcpz[0].length;j++)
          tblAtbCcpz[0][j].style.display="none"
         break
        case 'cp2_rcrd01':
         for(j=0;j<tblAtbCcpz[1].length;j++)
          tblAtbCcpz[1][j].style.display="none"
         break
        case 'cp3_rcrd01':
         for(j=0;j<tblAtbCcpz[2].length;j++)
          tblAtbCcpz[2][j].style.display="none"
         break
       }
      }
     }
    

    And finally here, a small .html file where all are "glued" together like so:

    <html>
    <!-- xml stacked transposed persons (rows with columns) paged list display data along with some sub-records like 1-n relationship -->
     <head>
     <meta charset="UTF-8" name="viewport" content="width=device-width, height=device-height, initial-scale=1.2"/>
      <title>PeopleList</title>
    <script src="../frameless-xslt2.min.js"></script> <!-- prhps some other xslt prc -->
      <script type="text/javascript" src="js/scrpt1.js"></script>
      <link rel="stylesheet" href="css/stbl.css"/>
     </head>
     <body>
      <h2 style="margin-left:1.6cm">People List</h2>
     <script type="application/xslt+xml" data-input="xml/prsns.xml" src="xml/prs_style.xsl"></script> 
     </body>
    </html>
    

    And still a small piece of .css down here:

    span:hover
    {
     cursor: pointer;
    }
    .cpz1, .cpz2, .cpz3
    { 
     display:none;
    }
    

    So .. this would be all. A couple of notes though ..

    • first, "unfortunatelly" the xslt processor used was ... frameless.js (frameless.io); this great old xslt processor is no longer available for download; they discontinued that great development, so use of it would prove very difficult right now; the reason one choose this one is for it's effectivness and simplicity; no need for prior compiling stuff and things like saxonJS does ..
    • don't claim to be the best answer, but it's a working solution;
    • this sort of layout is mere intended for mobiles where one does't have enough horizontal displaying room, that's why the vertical approach was picked for.
    • everything here actually works, even if I don't make some working case available; there are also some .js involved .. and it was a little bit difficult; point is everything depicted here is working !

    Thank you all for watching this and eventually hope for some other replies.