Avinash
Avinash

Reputation: 35

Merge common rows in PDF using XSL

I am New to XSL. I have an XML file and I am using XSL to Generate pdf from it. I am able to display the below table in PDF using Fo, FO block,

enter image description here

This generates the table perfectly with all data in different rows.

However, I need to display the Below format with merging

enter image description here

Below is the xml and The XSL code I have Tried:

XML

"<DocumentElement>
  <Student>
    <Roll>1</Roll>
    <NAME>Mark</NAME>
    <Subject>1000502</Subject>
    <DESCRIPTION>Test_2046_1</DESCRIPTION>
    <Total>20</Total>
  </Student>
  <Student>
    <Roll>1</Roll>
    <NAME>Mark</NAME>
    <Subject>1117697</Subject>
    <DESCRIPTION>Test_2046_2</DESCRIPTION>
    <Total>20</Total>
  </Student>
  <Student>
    <Roll>2</Roll>
    <NAME>Henry</NAME>
    <Subject>1271267</Subject>
    <DESCRIPTION>Test_2046_3</DESCRIPTION>
    <Total>20</Total>
  </Student>
  <Student>
    <Roll>2</Roll>
    <NAME>Henry</NAME>
    <Subject>5013025</Subject>
    <Total>20</Total>
  </Student>
</DocumentElement>"

XSL

"<xsl:template match="DocumentElement">
    <fo:block break-before="page">
      <fo:table xsl:use-attribute-sets="data_table">
        <xsl:call-template name="StudentItemsHeading"/>
        <fo:table-body>
          <xsl:apply-templates select="Student"/>
        </fo:table-body>
      </fo:table>
    </fo:block>
  </xsl:template>
  <xsl:template name="StudentItemsHeading">
    <fo:table-header>
      <fo:table-row xsl:use-attribute-sets="table_headers">
        <fo:table-cell xsl:use-attribute-sets="bordered">
          <fo:block>Student ID#</fo:block>
        </fo:table-cell>
        <fo:table-cell xsl:use-attribute-sets="bordered">
          <fo:block>Student Name</fo:block>
        </fo:table-cell>
        <fo:table-cell xsl:use-attribute-sets="bordered">
          <fo:block>Subjects</fo:block>
        </fo:table-cell>
        <fo:table-cell xsl:use-attribute-sets="bordered">
          <fo:block>Subject Description</fo:block>
        </fo:table-cell>
        <fo:table-cell xsl:use-attribute-sets="bordered">
          <fo:block>Total Marks</fo:block>
        </fo:table-cell>
        <fo:table-cell xsl:use-attribute-sets="bordered">
          <fo:block>Min.</fo:block>
        </fo:table-cell>
        <fo:table-cell xsl:use-attribute-sets="bordered">
          <fo:block>Max.</fo:block>
        </fo:table-cell>
      </fo:table-row>
    </fo:table-header>
  </xsl:template>
  <xsl:template match="Student">
    <fo:table-row>
      <fo:table-cell xsl:use-attribute-sets="bordered">
        <fo:block white-space-collapse="false" xsl:use-attribute-sets="bold">
          <xsl:value-of select="Roll"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="bordered">
        <fo:block>
          <xsl:value-of select="NAME"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="bordered">
        <fo:block white-space-collapse="false" xsl:use-attribute-sets="bold">
          <xsl:value-of select="Subject"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="bordered">
        <fo:block white-space-collapse="false" xsl:use-attribute-sets="bold">
          <xsl:value-of select="DESCRIPTION"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="number_format bordered">
        <fo:block>
          <xsl:value-of select="Total"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="number_format bordered">
        <fo:block>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="number_format bordered">
        <fo:block>
        </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </xsl:template>

Please Help on how to Achieve this.

Upvotes: 1

Views: 149

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167716

Instead of

<xsl:apply-templates select="Student"/>

use

<xsl:for-each-group select="Student" group-by="Roll">
  <xsl:apply-templates select="current-group()"/>
</xsl:for-each-group>

then in the template for Student use e.g.

  <xsl:template match="Student">
    <fo:table-row>
      <xsl:if test="position() = 1">
       <fo:table-cell xsl:use-attribute-sets="bordered" number-rows-spanned="{count(current-group())}">
        <fo:block white-space-collapse="false" xsl:use-attribute-sets="bold">
          <xsl:value-of select="Roll"/>
        </fo:block>
       </fo:table-cell>
       <fo:table-cell xsl:use-attribute-sets="bordered" number-rows-spanned="{count(current-group())}">
        <fo:block>
          <xsl:value-of select="NAME"/>
        </fo:block>
       </fo:table-cell>
      </xsl:if>
      <fo:table-cell xsl:use-attribute-sets="bordered">
        <fo:block white-space-collapse="false" xsl:use-attribute-sets="bold">
          <xsl:value-of select="Subject"/>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="bordered">
        <fo:block white-space-collapse="false" xsl:use-attribute-sets="bold">
          <xsl:value-of select="DESCRIPTION"/>
        </fo:block>
      </fo:table-cell>
      <xsl:if test="position() = 1">
       <fo:table-cell xsl:use-attribute-sets="number_format bordered" number-rows-spanned="{count(current-group())}">
        <fo:block>
          <xsl:value-of select="Total"/>
        </fo:block>
       </fo:table-cell>
      </xsl:if>
      <fo:table-cell xsl:use-attribute-sets="number_format bordered">
        <fo:block>
        </fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="number_format bordered">
        <fo:block>
        </fo:block>
      </fo:table-cell>
    </fo:table-row>
  </xsl:template>

That assumes using XSLT 2 or 3 with e.g. Saxon 9 or 10.

Upvotes: 2

Related Questions