XSLT - Produce address labels
UPDATE Rephrasing the question to clarify confusion.
I am using XSLT and XSL:FO translated by Apache FOP. I want to print address labels.
INPUT
<?xml version="1.0" encoding="utf-8" ?>
<workOrders>
<workOrder>
<number>111</number>
<PartNumber>110022</PartNumber>
<col3>222</col3>
<Qty>333</Qty>
</workOrder>
<workOrder>
<number>111</number>
<PartNumber>110022</PartNumber>
<col3>222</col3>
<Qty>333</Qty>
</workOrder>
<!--Manually copy/paste the workOrder until you have 47 of them..-->
</workOrders>
OUTPUT
Page 1 (full page 6 rows x 3 cols)Page 2 is same as page 1.
Page 3 (partial page...in this case 4 rows x 3 columns and last item blank)
UPDATE2 I plugged in Alejandro's solution. I'm getting an error reported by Apache FOP saying
xsl:template is not allowed in this position in the stylesheet
Here's the code translated from the HTML stuff to the XSL:FO. The point of error is marked by comment. What did I screw up?
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<fo:root xmlns:fo="http://www开发者_C百科.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<!-- layout for the first page -->
<fo:simple-page-master master-name="first"
page-height="11in"
page-width="8.5in"
margin-top="1cm"
margin-bottom="1cm"
margin-left="1cm"
margin-right="1cm">
<fo:region-body margin-top="0cm"/>
<fo:region-before extent="1cm"/>
<fo:region-after extent="0cm"/>
</fo:simple-page-master>
<!-- layout for the other pages -->
<fo:simple-page-master master-name="rest"
page-height="11in"
page-width="8.5in"
margin-top="1cm"
margin-bottom="1cm"
margin-left="1cm"
margin-right="1cm">
<fo:region-body margin-top="0cm"/>
<fo:region-before extent="1cm"/>
<fo:region-after extent="0cm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="basicPSM" >
<fo:repeatable-page-master-alternatives>
<fo:conditional-page-master-reference master-reference="first" page-position="first" />
<fo:conditional-page-master-reference master-reference="rest" page-position="rest" />
<!-- recommended fallback procedure -->
<fo:conditional-page-master-reference master-reference="rest" />
</fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>
</fo:layout-master-set>
<!-- end: defines page layout -->
<!-- actual layout -->
<fo:page-sequence master-reference="basicPSM">
<fo:flow flow-name="xsl-region-body">
<xsl:template match="/" name="tables"><!--ERROR REFERS TO HERE-->
<xsl:param name="pRows" select="3"/>
<xsl:param name="pColumns" select="3"/>
<xsl:param name="pSequence" select="*/*"/>
<xsl:variable name="vSize" select="$pRows * $pColumns"/>
<xsl:for-each select="$pSequence[position() mod $vSize = 1]">
<xsl:variable name="vPosition" select="position()"/>
<fo:table table-layout="fixed" width="63mm" border-collapse="separate" wrap-option="wrap">
<fo:table-body wrap-option="wrap">
<xsl:call-template name="rows">
<xsl:with-param name="pSequence"
select="$pSequence[
position() > ($vPosition - 1) * $vSize
and
$vPosition * $vSize + 1 > position()
]"/>
</xsl:call-template>
</fo:table-body>
</fo:table>
</xsl:for-each>
</xsl:template>
<xsl:template name="rows">
<xsl:param name="pSequence" select="/.."/>
<xsl:param name="pRow" select="$pRows"/>
<xsl:if test="$pRow">
<xsl:call-template name="rows">
<xsl:with-param name="pSequence" select="$pSequence"/>
<xsl:with-param name="pRow" select="$pRow - 1"/>
</xsl:call-template>
<fo:table-row wrap-option="wrap">
<xsl:call-template name="columns">
<xsl:with-param name="pSequence"
select="$pSequence[
position() > ($pRow - 1) * $pColumns
and
$pRow * $pColumns + 1 > position()
]"/>
</xsl:call-template>
</fo:table-row>
</xsl:if>
</xsl:template>
<xsl:template name="columns">
<xsl:param name="pSequence" select="/.."/>
<xsl:param name="pColumn" select="$pColumns"/>
<xsl:if test="$pColumn">
<xsl:call-template name="columns">
<xsl:with-param name="pSequence" select="$pSequence"/>
<xsl:with-param name="pColumn" select="$pColumn - 1"/>
</xsl:call-template>
<fo:table-cell width="90mm">
<fo:block wrap-option="wrap">
<xsl:apply-templates select="$pSequence[$pColumn]"/>
</fo:block>
</fo:table-cell>
</xsl:if>
</xsl:template>
<xsl:output method="xml"/>
<xsl:template match="/">
<xsl:call-template name="tables">
<xsl:with-param name="pSequence" select="workOrders/workOrder[position()!=1]"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="workOrder">
<xsl:value-of select="PartNumber"/>
</xsl:template>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:stylesheet>
This XSLT 1.0 stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="pRows" select="6"/>
<xsl:param name="pColumns" select="3"/>
<xsl:variable name="pCells" select="$pRows * $pColumns"/>
<xsl:template match="workOrders">
<xsl:apply-templates
select="workOrder[position() mod $pCells = 1]"
mode="table"/>
</xsl:template>
<xsl:template match="workOrder" mode="table">
<table>
<xsl:apply-templates
select="(.|following-sibling::workOrder
[$pCells > position()])
[position() mod $pColumns = 1]"
mode="row"/>
</table>
</xsl:template>
<xsl:template match="workOrder" mode="row">
<tr>
<xsl:apply-templates
select="(.|following-sibling::workOrder
[$pColumns > position()])"
mode="cell"/>
</tr>
</xsl:template>
<xsl:template match="workOrder" mode="cell">
<td>
<xsl:value-of select="PartNumber"/>
</td>
</xsl:template>
</xsl:stylesheet>
Output (with 47 workOrder
s):
<table>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
</table>
<table>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
</table>
<table>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
<td>110022</td>
</tr>
<tr>
<td>110022</td>
<td>110022</td>
</tr>
</table>
If you know there are no more than 18 orders, you could use something like this:
<xsl:if test="Order">
<tableRow>
<xsl:apply-templates select="Order[position() <= 6]" />
</tableRow>
<xsl:if test="Order[7]">
<tableRow>
<xsl:apply-templates select="Order[position() <= 12 and position() > 6]" />
</tableRow>
<xsl:if test="Order[13]">
<tableRow>
<xsl:apply-templates select="Order[position() <= 18 and position() > 12]" />
</tableRow>
</xsl:if>
</xsl:if>
</xsl:if>
and then you have a template that matches "Order"
and outputs a table cell.
Not maximally elegant, but easy.
Update:
OK, found out that the above was not what the OP wanted.
Below is a partial solution for the rephrased question. Disclaimers:
I do not know FO, so I am leaving that part as pseudocode. Judging by the question title I assume that the part you want help with is just the XSLT.
Not being sure whether you're needing answers about the gross structure of the page, or the formatting of each cell, or both, I've addressed the former and not the latter. I'll hold off on spending time on the latter unless I hear from you that that's what you need. Again, not knowing FO, I don't know whether you can format each cell's contents as an embedded table, which would be the simplest way to line up its columns...
Anyway, here is the partial solution:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:variable name="rowsPerPage" select="6"/>
<xsl:variable name="columns" select="3"/>
<xsl:variable name="cellsPerPage" select="$rowsPerPage * $columns"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="workOrders">
<xsl:for-each-group select="workOrder"
group-by="position() idiv $cellsPerPage">
<!-- <page> is pseudocode for FO markup -->
<page>
<xsl:for-each-group select="current-group()"
group-by="position() idiv $columns">
<!-- <row> is pseudocode for FO markup -->
<row>
<xsl:apply-templates select="current-group()" mode="cell"/>
</row>
</xsl:for-each-group>
</page>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="workOrder" mode="cell">
<!-- <cell> is pseudocode for FO markup -->
<cell>
<!-- here goes code for laying out the address label -->
</cell>
</xsl:template>
</xsl:stylesheet>
精彩评论