问题
I'm working on an XSL FO to generate PDF using FOP.NET. I've a requirement of generating the columns dynamically based on the XML i get from the DB. Below is the XML format i've and i need to generate the columns dynamically rather than hardcoding them in the xsl fo stylesheet. ANy help would be greatly appreciated.
Edit:
My goal is to build 20 types of reports and want to do it dynamically with 1 xsl fo. Is this possbile? or do I need to have 20 xsl fo files to generate the report? Please suggest an optimal way to do this.. I dont want to use itextsharp and other paid tools. (Only XSL FO)
Below is the XML that i get from SQL Server.
<?xml version="1.0" standalone="yes"?>
<Products>
<Product id="1" name="Rendezvous with Rama by Arthur C. Clarke" price="15" quantity="3" description="An all-time science fiction classic, Rendezvous with Rama is also one of Clarke's best novels--it won the Campbell, Hugo, Jupiter, and Nebula Awards." />
<Product id="2" name="Dune Chronicles by Frank Herbert" price="60" quantity="5" description="Dune is one of the most famous science fiction novels ever written, and deservedly so. The setting is elaborate and ornate, the plot labyrinthine, the adventures exciting. Five sequels follow." />
<Product id="3" name="Schindler's List by Thomas Keneally" price="21" quantity="6" description="A mesmerizing novel based on the true story of Oskar Schindler, a German industralist who saved and succored more than 1000 Jews from the Nazis at enormous financial and emotional expense." />
<Product id="4" name="Middle Passage by Charles Johnson" price="17" quantity="4" description="In this savage parable of the African American experience, Rutherford Calhoun, a newly freed slave eking out a living in New Orleans in 1830, hops aboard a square rigger to evade the prim Boston schoolteacher who wants to marry him. But the Republic turns out to be a slave clipper bound for Africa." />
<Product id="5" name="Underworld:A Novel by Don DeLillo" price="14" quantity="3" description="Underworld opens with a breathlessly graceful prologue set during the final game of the Giants-Dodgers pennant race in 1951. Written in what DeLillo calls super-omniscience the sentences sweep from young Cotter Martin as he jumps the gate to the press box, soars over the radio waves, runs out to the diamond, slides in on a fast ball, pops into the stands where J. It's an absolutely thrilling literary moment." />
<Product id="6" name="Stones from the River by Ursula Hegi" price="16" quantity="4" description="Ursula Hegi's Stones from the River clamors for comparisons to Gunter Grass's The Tin Drum; her protagonist Trudi Montag--like the unforgettable Oskar Mazerath--is a dwarf living in Germany during the two World Wars. " />
<Product id="7" name="Empire of the Sun by J. G. Ballard" price="12" quantity="3" description="Ballard's enduring novel of war and deprivation, internment camps and death marches, and starvation and survival is an honest coming-of-age tale set in a world thrown utterly out of joint." />
</Products>
The columns id, name, price, quantity, description need to be bound dynamically. Any help with an example would be greatly appreciated.
My Hardcoded XSL stylesheet
<fo:table border-bottom-width="5pt" width="1500pt" border-bottom-color="rgb(0,51,102)" border-collapse="collapse" background-color="rgb(255,255,255)">
<fo:table-column column-width="proportional-column-width(6.77)" column-number="1"/>
<fo:table-column column-width="proportional-column-width(5.09)" column-number="2"/>
<fo:table-column column-width="proportional-column-width(5.63)" column-number="3"/>
<fo:table-column column-width="proportional-column-width(5.94)" column-number="4"/>
<fo:table-column column-width="proportional-column-width(5.79)" column-number="5"/>
<fo:table-header>
<fo:table-row height="20.81pt" display-align="center" overflow="hidden">
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Transaction</fo:block>
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Date</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Cust ID</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Cust No</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Client Name</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Long ID</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<fo:table-row display-align="before">
<fo:table-cell text-align="center" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-left-width="1pt" border-right-width="1pt" border-top-width="1pt" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block>
1
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="left" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-left-width="1pt" border-right-width="1pt" border-top-width="1pt" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block>
Rendezvous with Rama by Arthur C. Clarke
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="right" border-top-color="rgb(0, 0, 0)" border-right-color="rgb(0, 0, 0)" border-top-style="solid" border="1pt " padding="2pt">
<fo:block>
3
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="right" border-top-style="solid" border="1pt rgb(0, 0, 0)" padding="2pt">
<fo:block>
$15.00
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="left" border-top-color="rgb(0, 0, 0)" border-left-color="rgb(0, 0, 0)" border-top-style="solid" border="1pt " padding="2pt">
<fo:block>
An all-time science fiction classic, Rendezvous with Rama is also one of Clarke's best novels--it won the Campbell, Hugo, Jupiter, and Nebula Awards.
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
Thanks, Pavan
回答1:
An XSLT 1.0 stylesheet for your sample is below. If you need to produce 20 variations on this, I suggest that you come up with an XML representation of the necessary information for each report -- e.g., the order and column-width for each of your attributes -- then use XSLT on that XML to generate an XSLT stylesheet like the one below. You can then use that XSLT to generate the FO from the XML that you get from SQL Server. It may sound complicated, but it should be simpler than trying to maintain 20 stylesheets.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<xsl:variable name="columnFontType" select="'sans-serif'"/>
<xsl:variable name="columnFontSize" select="'12pt'"/>
<xsl:template match="Products">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="a">
<fo:region-body margin="10mm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="a">
<fo:flow flow-name="xsl-region-body">
<fo:table border-bottom-width="5pt" border-bottom-color="rgb(0,51,102)" border-collapse="collapse" background-color="rgb(255,255,255)">
<fo:table-column column-width="proportional-column-width(6.77)" column-number="1"/>
<fo:table-column column-width="proportional-column-width(5.09)" column-number="2"/>
<fo:table-column column-width="proportional-column-width(5.63)" column-number="3"/>
<fo:table-column column-width="proportional-column-width(5.94)" column-number="4"/>
<fo:table-column column-width="proportional-column-width(5.79)" column-number="5"/>
<fo:table-header>
<fo:table-row height="20.81pt" display-align="center" overflow="hidden">
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Transaction</fo:block>
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Date</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Cust ID</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Cust No</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Client Name</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">Long ID</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<xsl:apply-templates />
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="Product">
<fo:table-row display-align="before">
<xsl:call-template name="cell">
<xsl:with-param name="value" select="@id"/>
</xsl:call-template>
<xsl:call-template name="cell">
<xsl:with-param name="value" select="@name"/>
</xsl:call-template>
<xsl:call-template name="cell">
<xsl:with-param name="value" select="@quantity"/>
</xsl:call-template>
<xsl:call-template name="cell">
<xsl:with-param name="value" select="format-number(@price, '$0.00')"/>
</xsl:call-template>
<xsl:call-template name="cell">
<xsl:with-param name="value" select="@description"/>
</xsl:call-template>
</fo:table-row>
</xsl:template>
<xsl:template name="cell">
<xsl:param name="value" />
<fo:table-cell text-align="center" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-left-width="1pt" border-right-width="1pt" border-top-width="1pt" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
<fo:block>
<xsl:value-of select="$value"/>
</fo:block>
</fo:table-cell>
</xsl:template>
</xsl:stylesheet>
Also look into xsl:attribute-set
(see https://www.w3.org/TR/xslt#attribute-sets) as a way to add a bunch of attributes at once (though possibly less useful if you're generating the XSLT anyway).
回答2:
My goal is to build 20 types of reports and want to do it dynamically with 1 xsl fo. Is this possbile?
It's possible - if all the reports follow some common pattern.
For example, if the rows are always children of the root element, and the cells are the attributes of rows, you could do something like this (code simplified for the purpose of demonstration):
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<table>
<header>
<row>
<xsl:for-each select="*[1]/@*">
<cell>
<xsl:value-of select="name()"/>
</cell>
</xsl:for-each>
</row>
</header>
<body>
<xsl:for-each select="*">
<row>
<xsl:for-each select="@*">
<cell>
<xsl:value-of select="."/>
</cell>
</xsl:for-each>
</row>
</xsl:for-each>
</body>
</table>
</xsl:template>
</xsl:stylesheet>
Applied to your input example, the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<table>
<header>
<row>
<cell>id</cell>
<cell>name</cell>
<cell>price</cell>
<cell>quantity</cell>
<cell>description</cell>
</row>
</header>
<body>
<row>
<cell>1</cell>
<cell>Rendezvous with Rama by Arthur C. Clarke</cell>
<cell>15</cell>
<cell>3</cell>
<cell>An all-time science fiction classic, Rendezvous with Rama is also one of Clarke's best novels--it won the Campbell, Hugo, Jupiter, and Nebula Awards.</cell>
</row>
<row>
<cell>2</cell>
<cell>Dune Chronicles by Frank Herbert</cell>
<cell>60</cell>
<cell>5</cell>
<cell>Dune is one of the most famous science fiction novels ever written, and deservedly so. The setting is elaborate and ornate, the plot labyrinthine, the adventures exciting. Five sequels follow.</cell>
</row>
<row>
<cell>3</cell>
<cell>Schindler's List by Thomas Keneally</cell>
<cell>21</cell>
<cell>6</cell>
<cell>A mesmerizing novel based on the true story of Oskar Schindler, a German industralist who saved and succored more than 1000 Jews from the Nazis at enormous financial and emotional expense.</cell>
</row>
<row>
<cell>4</cell>
<cell>Middle Passage by Charles Johnson</cell>
<cell>17</cell>
<cell>4</cell>
<cell>In this savage parable of the African American experience, Rutherford Calhoun, a newly freed slave eking out a living in New Orleans in 1830, hops aboard a square rigger to evade the prim Boston schoolteacher who wants to marry him. But the Republic turns out to be a slave clipper bound for Africa.</cell>
</row>
<row>
<cell>5</cell>
<cell>Underworld:A Novel by Don DeLillo</cell>
<cell>14</cell>
<cell>3</cell>
<cell>Underworld opens with a breathlessly graceful prologue set during the final game of the Giants-Dodgers pennant race in 1951. Written in what DeLillo calls super-omniscience the sentences sweep from young Cotter Martin as he jumps the gate to the press box, soars over the radio waves, runs out to the diamond, slides in on a fast ball, pops into the stands where J. It's an absolutely thrilling literary moment.</cell>
</row>
<row>
<cell>6</cell>
<cell>Stones from the River by Ursula Hegi</cell>
<cell>16</cell>
<cell>4</cell>
<cell>Ursula Hegi's Stones from the River clamors for comparisons to Gunter Grass's The Tin Drum; her protagonist Trudi Montag--like the unforgettable Oskar Mazerath--is a dwarf living in Germany during the two World Wars. </cell>
</row>
<row>
<cell>7</cell>
<cell>Empire of the Sun by J. G. Ballard</cell>
<cell>12</cell>
<cell>3</cell>
<cell>Ballard's enduring novel of war and deprivation, internment camps and death marches, and starvation and survival is an honest coming-of-age tale set in a world thrown utterly out of joint.</cell>
</row>
</body>
</table>
来源:https://stackoverflow.com/questions/37916438/xsl-fo-generate-dynamics-columns