I'm looking for a method to generate a Bar Chart in XSLT using Java Apache FOP.
I'm trying to generate bar chart with below XML and XSLT but its generating empty .PDF file without any chart?
data.xml
<?xml version="1.0" encoding="UTF-8"?>
<sales>
<region>
<title>Eastern Region Quarterly Sales (Second/'04)</title>
<key1 area="New York Area">.95</key1>
<key2 area="Virginia Area">.89</key2>
<key3 area="Maryland Area">.67</key3>
<key4 area="Connecticut Area">.65</key4>
<key5 area="Delaware Area">.45</key5>
</region>
</sales>
bar.xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:template match="sales">
<svg width="650" height="500">
<g id="axis" transform="translate(0 500) scale(1 -1)">
<line id="axis-y" x1="30" y1="20" x2="30" y2="450" style="fill:none;stroke:rgb(0,0,0);stroke-width:2" />
<line id="axis-x" x1="30" y1="20" x2="460" y2="20" style="fill:none;stroke:rgb(0,0,0);stroke-width:2" />
</g>
<xsl:apply-templates select="region" />
</svg>
</xsl:template>
<xsl:template match="region">
<g id="bars" transform="translate(30 479) scale(1 -430)">
<rect x="30" y="0" width="50" height="{key1}" style="fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:0" />
<rect x="100" y="0" width="50" height="{key2}" style="fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:0" />
<rect x="170" y="0" width="50" height="{key3}" style="fill:rgb(255,255,0);stroke:rgb(0,0,0);stroke-width:0" />
<rect x="240" y="0" width="50" height="{key4}" style="fill:rgb(0,255,255);stroke:rgb(0,0,0);stroke-width:0" />
<rect x="310" y="0" width="50" height="{key5}" style="fill:rgb(0,0,255);stroke:rgb(0,0,0);stroke-width:0" />
</g>
<g id="scale" transform="translate(29 60)">
<text id="scale1" x="0px" y="320px" style="text-anchor:end;fill:rgb(0,0,0);font-size:10;font-family:Arial">$25K</text>
<text id="scale2" x="0px" y="215px" style="text-anchor:end;fill:rgb(0,0,0);font-size:10;font-family:Arial">$50K</text>
<text id="scale3" x="0px" y="107.5px" style="text-anchor:end;fill:rgb(0,0,0);font-size:10;font-family:Arial">$75K</text>
<text id="scale4" x="0px" y="0px" style="text-anchor:end;fill:rgb(0,0,0);font-size:10;font-family:Arial">$100K</text>
</g>
<g id="key">
<rect id="key1" x="430" y="80" width="25" height="15" style="fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:1" />
<rect id="key2" x="430" y="100" width="25" height="15" style="fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1" />
<rect id="key3" x="430" y="120" width="25" height="15" style="fill:rgb(255,255,0);stroke:rgb(0,0,0);stroke-width:1" />
<rect id="key5" x="430" y="140" width="25" height="15" style="fill:rgb(0,255,255);stroke:rgb(0,0,0);stroke-width:1" />
<rect id="key4" x="430" y="160" width="25" height="15" style="fill:rgb(0,0,255);stroke:rgb(0,0,0);stroke-width:1" />
</g>
<text id="key1-text" x="465px" y="92px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key1/@area" />
</text>
<text id="key2-text" x="465px" y="112px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key2/@area" />
</text>
<text id="key3-text" x="465px" y="132px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key3/@area" />
</text>
<text id="key4-text" x="465px" y="152px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key4/@area" />
</text>
<text id="key5-text" x="465px" y="172px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key5/@area" />
</text>
<g id="title">
<text x="325px" y="20px" style="text-anchor:middle;fill:rgb(0,0,0);font-size:24;font-family:Arial">
<xsl:value-of select="title" />
</text>
</g>
</xsl:template>
</xsl:stylesheet>
I'm not sure why I'm getting empty pdf and I tried to generate svg file also - It also not showing any graph. Any help would be really appreciated.
You could create and embed an SVG in the XSL-FO using fo:instream-foreign-object
.
Since you're wanting to use XSLT and FOP, I'm assuming you have input data in XML. (If not, maybe XSLT and FOP aren't the right tools for the job?)
So the XSLT would create the XSL-FO and the embedded SVG from your XML input. FOP would create the PDF from the XSL-FO.
Example...
XML Input
<list>
<fruit>
<type>Apples</type>
<qty>5</qty>
</fruit>
<fruit>
<type>Oranges</type>
<qty>2</qty>
</fruit>
<fruit>
<type>Bananas</type>
<qty>7</qty>
</fruit>
<fruit>
<type>Peaches</type>
<qty>9</qty>
</fruit>
</list>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="my-page" page-width="8.5in" page-height="11in">
<fo:region-body margin="1in" margin-top="1.5in" margin-bottom="1.5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my-page">
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="list">
<fo:block>Example embedded SVG:</fo:block>
<fo:block space-before="4pt">
<fo:instream-foreign-object>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="420" height="150">
<title id="title">List of Fruit</title>
<xsl:apply-templates select="fruit">
<xsl:sort select="type" order="ascending" data-type="text"/>
</xsl:apply-templates>
</svg>
</fo:instream-foreign-object>
</fo:block>
</xsl:template>
<xsl:template match="fruit">
<xsl:variable name="y" select="((position() - 1) * 20) + (position() * 5 - 5)"/>
<g xmlns="http://www.w3.org/2000/svg">
<rect width="{qty * 10}" height="20" y="{$y}"/>
<text x="100" y="{$y + 10}" dy=".35em">
<xsl:value-of select="concat(qty,' ',type)"/>
</text>
</g>
</xsl:template>
</xsl:stylesheet>
XSL-FO Output
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="my-page" page-width="8.5in" page-height="11in">
<fo:region-body margin="1in" margin-top="1.5in" margin-bottom="1.5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my-page">
<fo:flow flow-name="xsl-region-body">
<fo:block>Example embedded SVG:</fo:block>
<fo:block space-before="4pt">
<fo:instream-foreign-object>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="420" height="150">
<title id="title">List of Fruit</title>
<g>
<rect width="50" height="20" y="0"/>
<text x="100" y="10" dy=".35em">5 Apples</text>
</g>
<g>
<rect width="70" height="20" y="25"/>
<text x="100" y="35" dy=".35em">7 Bananas</text>
</g>
<g>
<rect width="20" height="20" y="50"/>
<text x="100" y="60" dy=".35em">2 Oranges</text>
</g>
<g>
<rect width="90" height="20" y="75"/>
<text x="100" y="85" dy=".35em">9 Peaches</text>
</g>
</svg>
</fo:instream-foreign-object>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
The rendered PDF would be a single 8.5" x 11" page with the following content:
Notes:
UPDATED XSLT FROM MODIFIED QUESTION:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/2000/svg">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="my-page" page-width="8.5in" page-height="11in">
<fo:region-body margin="1in" margin-top="1.5in" margin-bottom="1.5in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my-page">
<fo:flow flow-name="xsl-region-body">
<fo:block>
<fo:instream-foreign-object>
<xsl:apply-templates/>
</fo:instream-foreign-object>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="sales">
<svg width="650" height="500">
<g id="axis" transform="translate(0 500) scale(1 -1)">
<line id="axis-y" x1="30" y1="20" x2="30" y2="450" style="fill:none;stroke:rgb(0,0,0);stroke-width:2" />
<line id="axis-x" x1="30" y1="20" x2="460" y2="20" style="fill:none;stroke:rgb(0,0,0);stroke-width:2" />
</g>
<xsl:apply-templates select="region" />
</svg>
</xsl:template>
<xsl:template match="region">
<g id="bars" transform="translate(30 479) scale(1 -430)">
<rect x="30" y="0" width="50" height="{key1}" style="fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:0" />
<rect x="100" y="0" width="50" height="{key2}" style="fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:0" />
<rect x="170" y="0" width="50" height="{key3}" style="fill:rgb(255,255,0);stroke:rgb(0,0,0);stroke-width:0" />
<rect x="240" y="0" width="50" height="{key4}" style="fill:rgb(0,255,255);stroke:rgb(0,0,0);stroke-width:0" />
<rect x="310" y="0" width="50" height="{key5}" style="fill:rgb(0,0,255);stroke:rgb(0,0,0);stroke-width:0" />
</g>
<g id="scale" transform="translate(29 60)">
<text id="scale1" x="0px" y="320px" style="text-anchor:end;fill:rgb(0,0,0);font-size:10;font-family:Arial">$25K</text>
<text id="scale2" x="0px" y="215px" style="text-anchor:end;fill:rgb(0,0,0);font-size:10;font-family:Arial">$50K</text>
<text id="scale3" x="0px" y="107.5px" style="text-anchor:end;fill:rgb(0,0,0);font-size:10;font-family:Arial">$75K</text>
<text id="scale4" x="0px" y="0px" style="text-anchor:end;fill:rgb(0,0,0);font-size:10;font-family:Arial">$100K</text>
</g>
<g id="key">
<rect id="key1" x="430" y="80" width="25" height="15" style="fill:rgb(255,0,0);stroke:rgb(0,0,0);stroke-width:1" />
<rect id="key2" x="430" y="100" width="25" height="15" style="fill:rgb(0,255,0);stroke:rgb(0,0,0);stroke-width:1" />
<rect id="key3" x="430" y="120" width="25" height="15" style="fill:rgb(255,255,0);stroke:rgb(0,0,0);stroke-width:1" />
<rect id="key5" x="430" y="140" width="25" height="15" style="fill:rgb(0,255,255);stroke:rgb(0,0,0);stroke-width:1" />
<rect id="key4" x="430" y="160" width="25" height="15" style="fill:rgb(0,0,255);stroke:rgb(0,0,0);stroke-width:1" />
</g>
<text id="key1-text" x="465px" y="92px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key1/@area" />
</text>
<text id="key2-text" x="465px" y="112px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key2/@area" />
</text>
<text id="key3-text" x="465px" y="132px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key3/@area" />
</text>
<text id="key4-text" x="465px" y="152px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key4/@area" />
</text>
<text id="key5-text" x="465px" y="172px" style="fill:rgb(0,0,0);font-size:18;font-family:Arial">
<xsl:value-of select="key5/@area" />
</text>
<g id="title">
<text x="325px" y="20px" style="text-anchor:middle;fill:rgb(0,0,0);font-size:24;font-family:Arial">
<xsl:value-of select="title" />
</text>
</g>
</xsl:template>
</xsl:stylesheet>
PDF Output