Monday, December 12, 2011

Table of Contents with subsections using XSL-FO

In Table of Contents using XSL-FO I explored creating table of contents using XSL-FO.

I needed to list subsections too. The way to do it is to loop through all subsections after you have listed the section in the TOC:
<xsl:for-each select="section">
<!-- Code to show TOC line for section -->
<xsl:for-each select="subsection">
<fo:block margin-left="10pt" text-align-last="justify">
<xsl:value-of select="subsectionheader" />
<fo:leader leader-pattern="dots" leader-length.maximum="100%" />
<fo:page-number-citation ref-id="{@subsectionid}" />
</fo:block>
</xsl:for-each>
</xsl:for-each>


Notice the margin-left="10pt" which makes an indent to show that the line represents a subsection.

Also remember to add a block in the subsection with id corresponding to the @subsectionid attribute which XSL 'retrieves' from XML above.
<fo:block id="{@subsectionid}" />

If you have subsections that you dont want to list you can wrap the block above in the following code:
<xsl:if test="@subsectionid">
...
</xsl:if>

which checks if the 'subsection' attribute has been set in XML, if not, it enter a line in the TOC.


See http://wiki.apache.org/xmlgraphics-fop/IndentInheritance
http://www.mail-archive.com/fop-users@xmlgraphics.apache.org/msg00300.html
http://www.herikstad.net/2011/12/table-of-contents-using-xsl-fo.html

Friday, December 9, 2011

Java Enum from value

There are different levels of using Enums in Java. From the simplest one:
public enum Color {
WHITE, BLACK, RED, YELLOW, BLUE;
}

to using constructor, values and methods:
public enum Color {
WHITE(21), BLACK(22), RED(23), YELLOW(24), BLUE(25);

private int code;

private Color(int c) {
code = c;
}

public int getCode() {
return code;
}

Note that the constructor can only be private or package default, to 'create' an Enum follow below:

To get an Enum from a value (e.g. after storing the value in DB) you can use valueOf() which looks up an Enum based on the given string. Or use values() to look it up directly in the array of possible values, e.g.:Color.values()[2];

Note: valueOf() may throw IllegalArgumentException so, check for that if you don't want a runtime exception.

Edit: From pk's comment and link below I discovered the correct way to use the valueOf() method is to pass the enum name, not the value. E.g. Color.valueOf("WHITE") would give the Color enum WHITE, instead of Color.valueOf("21") which would not. Thanks. :)

Code and thoughts found at: http://javahowto.blogspot.com/2008/04/java-enum-examples.html
http://stackoverflow.com/questions/2418729/whats-the-best-practice-to-look-up-java-enums
http://www.coderanch.com/t/401264/java/java/cast-int-enum

Java abstract classes

Pretty basic stuff, but nicely explained:

In Java:
- Abstract classes have one or more abstract method.
- Cannot be instantiated, but can:
  - Have a constructor (callable from subclasses using super()).
  - Be referenced (Figure f = new Rectangle()).
- Subclasses of abstract classes (Rectangle extends Figure) must implement the abstract methods or must themselves be abstract.

Read the tutorial: http://www.java-samples.com/showtutorial.php?tutorialid=288

Tuesday, December 6, 2011

Table of Contents using XSL-FO

XSL-FO lets you convert XML into formatted text for use on the web of in PDFs.

A neat feature to have in you PDFs is a table of content. In your fo:root tag, after setting the 'layout-master-set' and before handling the sections of your xml:
<fo:page-sequence master-reference="A4" force-page-count="no-force">
<xsl:call-template name="header"/>
<xsl:call-template name="footer"/>
<fo:flow flow-name="xsl-region-body" font-family="Arial" font-size="10pt">
<fo:block color="white" keep-with-next.within-page="always">&#160;</fo:block>
<fo:block background-color="white" text-align="center" border="2pt solid black" font-weight="bold" font-size="12pt" keep-with-next.within-page="always">
Contents
</fo:block>
<fo:block color="white" keep-with-next.within-page="always">&#160;</fo:block>
<xsl:for-each select="section">
<fo:block text-align-last="justify">
<xsl:value-of select="header"/>
<fo:leader leader-pattern="dots" leader-length.maximum="100%"/>
<fo:page-number-citation ref-id="{@sectionid}"/>
</fo:block>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>


Remember for XSL to find the place you are linking to, you need to create a block item with id attribute of the correct section id value:
<fo:block id="{@sectionid}" />
e.g.
<xsl:template match="section">
<fo:page-sequence master-reference="A4" force-page-count="no-force">
<xsl:call-template name="header"/>
<xsl:call-template name="footer"/>
<fo:flow flow-name="xsl-region-body" font-family="Arial" font-size="10pt">
<fo:block id="{@sectionid}" />
<xsl:apply-templates select="header" />
<xsl:apply-templates select="content" />
<xsl:apply-templates select="lastpage" />
</fo:flow>
</fo:page-sequence>
</xsl:template>



NOTE: ref-id may let you select the id with or without curly brackets "{@sectionid}" or "@sectionid".


Also if you want to have a clickable link to the pages listed wrap the line in a basic-link tag:
<fo:basic-link internal-destination="{@sectionid}"></fo:basic-link>
e.g.
<fo:block text-align-last="justify">
<fo:basic-link internal-destination="{@sectionid}">
<xsl:value-of select="header"/>
<fo:leader leader-pattern="dots" leader-length.maximum="100%"/>
<fo:page-number-citation ref-id="{@sectionid}"/>
</fo:basic-link>
</fo:block>


Sources:
http://www.mail-archive.com/fop-users@xmlgraphics.apache.org/msg00300.html
http://www.stylusstudio.com/xsllist/200503/post30180.html
http://www.dpawson.co.uk/xsl/sect3/N8703.html
http://www.xmlpdf.com/tableofcontents.html
http://stackoverflow.com/questions/541370/xslt-how-to-select-xml-attribute-by-attribute
http://www.dpawson.co.uk/xsl/examples.html