开发者

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)

XSLT - Produce address labels

Page 2 is same as page 1.

Page 3 (partial page...in this case 4 rows x 3 columns and last item blank)

XSLT - Produce address labels


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 workOrders):

<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() &lt;= 6]" />
  </tableRow>
  <xsl:if test="Order[7]">
    <tableRow>
      <xsl:apply-templates select="Order[position() &lt;= 12 and position() > 6]" />
    </tableRow>
    <xsl:if test="Order[13]">
      <tableRow>
        <xsl:apply-templates select="Order[position() &lt;= 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:

  1. 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.

  2. 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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜