X-Pippes
X-Pippes

Reputation: 1170

Convert XML to HTML using XSLT Pagination

I know there are some questions about this here, and I tried a lot of solutions around but i'm still stuck. I tried to use this pagination in xsl and this Possible to split XML into multiple pages with XSLT? but don't get what I need,

I need to create a pagination in my generated html, using a XML through a XSLT parser.

XML file is like this

<root>
    <result>
        <a>field one</a>
        <b>field two</b>
        <c>field three</c>
    </result>
    <result>
        <a>hello</a>
        <b>thanks</b>
        <c>for help</c>
    </result>
    <result>
        <a>thank</a>
        <b>you</b>
        <c>!!</c>
    </result>
    ..... 
</root>

and my XSLT without pagination is this

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    xmlns:user="http://mycompany.com/mynamespace">


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

    <xsl:template match="/">
        <html>
            <body>
                <xsl:apply-templates />
            </body>
        </html>
    </xsl:template>

    <xsl:template match="root">
                    <xsl:for-each select="result">
                        <div class="list_item">
                            <div class="dmv_line">
                                <div class="box_text">
                                    <h2><xsl:value-of select="a"/></h2>
                                </div>
                                </div>
                                <div class="dmv_line">
                                    <div class="box_text">
                                        <h2><xsl:value-of select="b"/></h2>
                                    </div>
                                </div>
                                <div class="dmv_line">
                                    <div class="box_text">
                                        <h2><xsl:value-of select="c"/></h2>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </xsl:for-each>
    </xsl:template>


</xsl:stylesheet>

What I need is to create a <div> that encapsulate results 3 by 3 or 4 by 4, which I will make hide or visible in javascript later.. Thanks

[EDIT]: The HTML output, if I assume to make pagination 2 elements per page, and considering only the 3 elements in example, the output should be

<-- page number one --->
<div id="1">
 <div class="list_item">
     <div class="dmv_line">
        <div class="box_text">
            <h2>field one</h2>
        </div>
     </div>
    <div class="dmv_line">
        <div class="box_text">
            <h2>field two</h2>
        </div>
     </div>
     <div class="dmv_line">
        <div class="box_text">
            <h2>field three</h2>
        </div>
     </div>
    </div>
     <div class="list_item">
         <div class="dmv_line">
            <div class="box_text">
                <h2>hello</h2>
            </div>
         </div>
        <div class="dmv_line">
            <div class="box_text">
                <h2>thanks</h2>
            </div>
         </div>
         <div class="dmv_line">
            <div class="box_text">
                <h2>for help</h2>
            </div>
         </div>
    </div>
</div>
 <-- END OF page number one --->
 <-- page number two --->
<div id="2">     
     <div class="list_item">
         <div class="dmv_line">
            <div class="box_text">
                <h2>thank</h2>
            </div>
         </div>
        <div class="dmv_line">
            <div class="box_text">
                <h2>you</h2>
            </div>
         </div>
         <div class="dmv_line">
            <div class="box_text">
                <h2>!!!</h2>
            </div>
         </div>
    </div>
</div>  
 <-- END OF page number two --->

Upvotes: 0

Views: 1685

Answers (1)

Tim C
Tim C

Reputation: 70608

For problems like this, the approach is to firstly select the elements that will occur first on each of your 'pages'. This is achieved by checking its position.

<xsl:for-each select="result[position() mod $size = 1]">

So, if the $size variable is set to 2, this would select the result elements in positions 1, 3, 5, etc...

Within this loop, you can then output the containing div tag for the 'age'

<div id="{position()}">  

Note that position is context-sensitive, and will return the position of the node in the node set you have just selected (i.e. it will return 1, 2, 3, etc)

Finally, to get the result elements that make up the 'page' you can select them like so

<xsl:apply-templates select="self::*|following-sibling::*[position() &lt; $size]" />

And the template that matches them would effectively be like your existing code in the xsl:for-each.

Try the following XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:param name="size" select="2"/>

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

   <xsl:template match="/">
      <html>
         <body>
            <xsl:apply-templates/>
         </body>
      </html>
   </xsl:template>

   <xsl:template match="root">
      <xsl:for-each select="result[position() mod $size = 1]">
         <div id="{position()}">
            <xsl:apply-templates select="self::*|following-sibling::*[position() &lt; $size]"/>
         </div>
      </xsl:for-each>
   </xsl:template>

   <xsl:template match="result">
      <div class="list_item">
         <div class="dmv_line">
            <div class="box_text">
               <h2>
                  <xsl:value-of select="a"/>
               </h2>
            </div>
         </div>
         <div class="dmv_line">
            <div class="box_text">
               <h2>
                  <xsl:value-of select="b"/>
               </h2>
            </div>
         </div>
         <div class="dmv_line">
            <div class="box_text">
               <h2>
                  <xsl:value-of select="c"/>
               </h2>
            </div>
         </div>
      </div>
   </xsl:template>
</xsl:stylesheet>

This should hopefully give you the output you need.

As an aside, you have a bit of code repetition in your code. Try replacing the template that matches result with these two templates instead:

<xsl:template match="result">
   <div class="list_item"> 
      <xsl:apply-templates select="a|b|c" />
   </div>
</xsl:template>

<xsl:template match="result/*">
      <div class="dmv_line">
         <div class="box_text">
            <h2>
               <xsl:value-of select="."/>
            </h2>
         </div>
       </div>
</xsl:template>

Upvotes: 1

Related Questions