Reputation: 147
I am trying to format my list using FORMATTING OBJECTS which is in this format.
XML
<SessionValues>
<SessionValue Name=\"Items\">
<Value>Item1</Value>
<Value>Item2</Value>
<Value>Item3</Value>
<Value>Item4</Value>
<Value>Item5</Value>
<Value>Item6</Value>
<Value>Item7</Value>
<Value>Item8</Value>
<Value>Item9</Value>
<Value>Item10</Value>
<Value>Item11</Value>
<Value>Item12</Value>
<Value>Item13</Value>
<Value>Item14</Value>
<Value>Item15</Value>
</SessionValue>
<SessionValues>
XSLT
<xsl:template match="Table[@Caption='Proofs']">
<fo:list-block >
<xsl:for-each select="key('sessionValues-id','Items')/Value">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<fo:inline>•</fo:inline>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()" text-align="left" font-size="10pt">
<fo:block text-align="left" font-size="10pt">
<xsl:value-of select="text()"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
This gives me a long list of all items. I need to show it in a way that if the number of items to be displayed are more than 5 it should appear in the next column. So for the example above there should be 3 column with 5 items each.
** UPDATE **
Expected Output
<fo:table>
<fo:table-body>
<fo:table-row>
<fo:table-cell>Item 1</fo:table-cell>
<fo:table-cell>Item 2</fo:table-cell>
<fo:table-cell>Item 3</fo:table-cell>
<fo:table-cell>Item 4</fo:table-cell>
<fo:table-cell>Item 5</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>Item 6</fo:table-cell>
<fo:table-cell>Item 7</fo:table-cell>
<fo:table-cell>Item 8</fo:table-cell>
<fo:table-cell>Item 9</fo:table-cell>
<fo:table-cell>Item 10</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>Item 11</fo:table-cell>
<fo:table-cell>Item 12</fo:table-cell>
<fo:table-cell>Item 13</fo:table-cell>
<fo:table-cell>Item 14</fo:table-cell>
<fo:table-cell>Item 15</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
** UPDATE - 2 **
I am following @Franks suggestion and have created some templates to be called depending on my condition. Something like this
<fo:table>
<fo:table-column number-columns-repeated="$columns" />
<fo:table-body>
<xsl:for-each select="key('sessionValues-id','Items')/Value">
<xsl:choose>
<xsl:when test="SomeCondition">
<!-- template with Row and Cell -->
</xsl:when>
<xsl:otherwise>
<!-- template with Cell -->
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</fo:table-body>
</fo:table>
I am not getting any errors but it is not even generating anything. I suspect it is <fo:table-column number-columns-repeated="$columns" />
Can anyone tell me how we can specify number of columns in my case dynamically ?? The count of number of columns is stored in variable $columns
.
Upvotes: 0
Views: 884
Reputation: 117102
To minimize the example to the problem at hand:
Given a well-formed input:
XML
<SessionValues>
<SessionValue Name="Items">
<Value>Item1</Value>
<Value>Item2</Value>
<Value>Item3</Value>
<Value>Item4</Value>
<Value>Item5</Value>
<Value>Item6</Value>
<Value>Item7</Value>
<Value>Item8</Value>
<Value>Item9</Value>
<Value>Item10</Value>
<Value>Item11</Value>
<Value>Item12</Value>
<Value>Item13</Value>
<Value>Item14</Value>
<Value>Item15</Value>
</SessionValue>
</SessionValues>
the following stylesheet:
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:variable name="columns" select="5" />
<xsl:template match="SessionValue">
<table>
<xsl:for-each select="Value[position() mod $columns = 1]" >
<tr>
<xsl:for-each select=". | following-sibling::Value[position() < $columns]">
<td><xsl:value-of select="."/></td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
will return:
Result
<?xml version="1.0" encoding="UTF-8"?>
<table>
<tr>
<td>Item1</td>
<td>Item2</td>
<td>Item3</td>
<td>Item4</td>
<td>Item5</td>
</tr>
<tr>
<td>Item6</td>
<td>Item7</td>
<td>Item8</td>
<td>Item9</td>
<td>Item10</td>
</tr>
<tr>
<td>Item11</td>
<td>Item12</td>
<td>Item13</td>
<td>Item14</td>
<td>Item15</td>
</tr>
</table>
Upvotes: 0
Reputation: 8068
Use break-after="column"
(or break-before="column"
) as appropriate. See https://www.w3.org/TR/xsl11/#d0e26492
Breaking to the next column requires that you've specified that there is a next column to break to. In XSL 1.1, you specify column-count
on fo:region-body
to set the column count for the fo:region-body
for the page-master. With AH Formatter, you can also set column-count
on an individual fo:block-container
(https://www.antennahouse.com/product/ahf63/ahf-ext.html#axf.column-count) as in the example below:
<xsl:template match="SessionValue">
<fo:block-container column-count="{ceiling(count(Value) div 5)}">
<fo:list-block>
<xsl:apply-templates select="Value" />
</fo:list-block>
</fo:block-container>
</xsl:template>
<xsl:template match="Value">
<fo:list-item>
<xsl:if test="position() mod 5 = 0">
<xsl:attribute name="break-after">column</xsl:attribute>
</xsl:if>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<fo:inline>•</fo:inline>
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()" text-align="left" font-size="10pt">
<fo:block text-align="left" font-size="10pt">
<xsl:value-of select="text()"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
This was in the XSL 2.0 requirements: https://www.w3.org/TR/xslfo20-req/#N66550
Other formatters may have different mechanisms.
Edit
But if you have a multi-column region (or fo:block-container
), the formatter can do a better job of balancing the columns based on formatted size than you can do by counting list items. If, for example, one or more of the list items had a lot of text and took up multiple lines but the others didn't, then you'd have uneven column heights if you manually inserted breaks after every fifth list item, whereas the formatter could break between columns based on the formatted sizes of the text.
Upvotes: 1
Reputation: 2066
You could try with the following code inside your loop:
<xsl:choose>
<xsl:when test="(position() mod 5) = 0">
<!-- You code for beginning a new column here -->
</xsl:when>
</xsl:choose>
<!-- here you output your list-item -->
<xsl:choose>
<xsl:when test="(position() mod 5) = 0">
<!-- You code for closing the new column here -->
</xsl:when>
</xsl:choose>
Not the most elegant solution but it should work.
Upvotes: 0