XSLT - 生成地址标签

发布于 2024-11-04 20:48:01 字数 6228 浏览 4 评论 0原文

更新重新表述问题以澄清混乱。

我正在使用由 Apache FOP 翻译的 XSLT 和 XSL:FO。我想打印地址标签。

输入

<?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>

输出
第 1 页(整页 6 行 x 3 列)
Page1

第 2 页与第 1 页相同。

第 3 页(部分页面...在本例中为 4 行 x 3 列,最后一项为空)

Page3


UPDATE2
I plugged in Alejandro's solution. I'm getting an error reported by Apache FOP saying

样式表中的此位置不允许使用 xsl:template

下面是从 HTML 内容转换为 XSL:FO 的代码。错误点已用注释标记。我搞砸了什么?

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <fo:root xmlns:fo="http://www.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>

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)
Page1

Page 2 is same as page 1.

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

Page3



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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别把无礼当个性 2024-11-11 20:48:01

此 XSLT 1.0 样式表:

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

输出(包含 47 个 workOrder):

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

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>
薄荷→糖丶微凉 2024-11-11 20:48:01

如果您知道订单不超过 18 个,则可以使用类似以下内容:

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

然后您就有一个与 "Order" 匹配并输出表格单元格的模板。

不是最优雅的,但很简单。

更新:

好的,发现上面的内容不是OP想要的。

以下是改写问题的部分解决方案。免责声明:

  1. 我不知道 FO,所以我将该部分保留为伪代码。从问题标题来看,我假设您需要帮助的部分只是 XSLT。

  2. 不确定您是否需要有关页面总体结构或每个单元格格式或两者的答案,我已经解决了前者而不是后者。我会推迟花时间在后者上,除非我听到你说这就是你所需要的。再说一遍,不知道 FO,我不知道您是否可以将每个单元格的内容格式化为嵌入表格,这将是排列其列的最简单方法...

无论如何,这是部分解决方案:

<?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>

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:

  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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文