I am on the way to generate labels via XSL:FO. The labels will the same text. So my PDF page is made of a table with simply the n-times same rows until the page ends:
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select = "foo"/>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select = "bar"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
I do not want to copy and paste the code n-times to fill a page. I tried to some kind of a loop the adds n-times the row.
I found this construct:
<xsl:for-each select="1 to 20">..</xsl:for-each>
Did not work but raised an error.
Any easy way to loop in XSL:FO?
Thanks in advance.
As @martin-honnen said moments ago, but with code:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="xs" version="2.0">
<xsl:variable name="root" select="/" />
<xsl:template match="/">
<xsl:for-each select="1 to 10">
<xsl:for-each select="$root">
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select="foo" />
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="bar" />
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Inside the <xsl:for-each select="1 to 10">
, the context is the current integer value of the 1 to 10
, and you can't select nodes relative to an integer. You need to reestablish the context by making a variable for what was the current node and use that variable either in an inner xsl:for-each
(as above) or in your select
attributes. Which is better is largely a matter of personal preference, which can come down to how many times you'd have to repeat the variable reference in select
attributes.
If you are stuck with using XSLT 1.0, the xsl:for-each
needs to be able to select enough nodes (from anywhere, really) to be able to repeat the right number of times:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="xs" version="1.0">
<xsl:variable name="document" select="/*" />
<xsl:template match="/*">
<xsl:for-each select="(//node())[position() <= 10]">
<xsl:for-each select="$document">
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select="foo" />
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="bar" />
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
However, IMO it would be better to instead forget about the xsl:for-each
, etc., and do it recursively:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="xs" version="1.0">
<xsl:template match="/*" name="row">
<xsl:param name="count" select="1" />
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select="foo" />
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="bar" />
</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:if test="$count < 10">
<xsl:call-template name="row">
<xsl:with-param name="count" select="$count + 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>