2

我有一个 XML 输入文件,可以说它shipnote.xml包含一个部分项目列表。部分项具有通常的属性qty和。每个项目都分配给一个.partnolabelpacketno

我写了一个 xsl 文件来从这些数据中生成一个 pdf-shipnote。要求是,每个packetno都应从 pdf 文档中的新页面开始。每页最多有 5 个项目。

我试图做的是,首先选择不同PCKNO的 s 并遍历这个不同packetno的 s。然后我在第一个循环中嵌入了第二个循环来检索每篇文章PCKNO,并将它们打印在 Shipnote 上。

接下来您可以看到来自 ship.xml 的示例数据:

root>
 items>

 item PCKNO="1" PCKCNT="2" > QTY>2/QTY> PARTNO>1518/PARTNO> LABEL>Part12/LABEL> /item>
 item PCKNO="1" PCKCNT="2" > QTY>1/QTY> PARTNO>1519/PARTNO> LABEL>Partxy/LABEL> /item>
 item PCKNO="2" PCKCNT="2" > QTY>3/QTY> PARTNO>1518/PARTNO> LABEL>Part12/LABEL> /item>
 item PCKNO="2" PCKCNT="2" > QTY>2/QTY> PARTNO>1519/PARTNO> LABEL>Partxy/LABEL> /item>

 /items>

/root>

此布局是必需的:

pdf-Page 1, <b>PCKNO:</b> 1
qty | Partno | Label    |  
----|--------|----------| 
2   | 1518   | Part123  | 
1   | 1519   | Partxyz  | 

pdf-Page 2, <b>PCKNO:</b> 2
qty | Partno | Label    | 
----|--------|----------|
3   | 1518   | Part123  |
2   | 1520   | Partfour |

然后我应用了 xsl-stylesheet 来满足要求。

外部循环完成:

fo:table table-layout='fixed' width="100%" >
    !-- Columns of shipnote-->
    fo:table-column />
    fo:table-column />
    fo:table-column />
    fo:table-header >
        fo:table-row >
            fo:table-cell><fo:block font-weight="bold">Qty /fo:block>    /fo:table-cell>
            fo:table-cell><fo:block font-weight="bold">Partno. /fo:block> /fo:table-cell>
            fo:table-cell><fo:block font-weight="bold">Partname /fo:block> /fo:table-cell>
        /fo:table-row >
    /fo:table-header>

    fo:table-body>

 !-- outer Loop get distinct pckno-->
xsl:for-each select="items/item[not(@PCKNO=preceding-sibling::position/@PCKNO)]/@PCKNO"
 xsl:variable name="packno" select="."/>    
 !-- inner loop get items per pckno-->
 xsl:for-each select="items/item[@PCKNO = $packno]" >   

    fo:table-row keep-together="always">
        !-- paximum of 5 parts per page-->
        xsl:if test="position() mod 5 = 1">
            xsl:attribute name="break-before">page/xsl:attribute>
        /xsl:if> 
        fo:table-cell>fo:block> xsl:value-of select="QTY"/> /fo:block> /fo:table-cell>
        fo:table-cell>fo:block> xsl:value-of select="PARTNO"/> /fo:block> /fo:table-cell>
        fo:table-cell>fo:block> xsl:value-of select="LABEL"/> /fo:block> /fo:table-cell>
    /fo:table-row>   

 /xsl:for-each>

/xsl:for-each>

我正在使用这个 fop 命令:fop -xsl shiptest.xsl -xml shiptest.xml -pdf shiptest.pdf

结果是:

     Exception

 - org.apache.fop.apps.FOPException: <b>org.apache.fop.fo.ValidationException: "fo:table-body" is missing child elements. </b>Required content model: marker* (table-row+|table-cell+) (no contextinfo available)

 - javax.xml.transform.TransformerException: <b>org.apache.fop.fo.ValidationException: "fo:table-body" is missing child elements. </b>Required content model: marker* (table-row+|table-cell+) (no contextinfo available)

当我剥离外循环并仅使用具有恒定参数 1、2 的内循环时,它可以按需要工作:

  xsl:for-each select="items/item[@PCKNO = <b>1</b>]"   /xsl:for-each
  xsl:for-each select="items/item[@PCKNO = <b>2</b>]"   /xsl:for-each

但我需要它是动态的。我被困在这一点上。请给我一个提示如何解决这个问题。

4

1 回答 1

3

这是xsl:for-each你遇到的麻烦......

<xsl:for-each select="items/item[not(@PCKNO=preceding-sibling::position/@PCKNO)]/@PCKNO">

这有两个问题...

  1. 您正在做preceding-sibling::position,但您的 XML 中没有元素名称位置

  2. 您正在xsl:for-each中选择@PCKNO属性,这意味着内部xsl:for-each将与该属性相关。但是您的内部xsl:for-each正在选择items/item,因此它不会选择任何内容。

因此,“最简单”的解决方法是将第一个xsl:for-each更改为此

<xsl:for-each select="items/item[not(@PCKNO=preceding-sibling::item/@PCKNO)]">

因此,此时您位于item元素上。因此,需要将内部的xsl:for-each更改为 this,这样它就可以回到父元素,然后可以选择所有具有相同@PCKNO属性的item元素。

<xsl:for-each select="../item[@PCKNO = $packno]">

值得注意的是,使用前同级并不是寻找不同元素的特别有效的方法。在 XLST 1.0 中,进行分组的最有效方法是使用一种称为Muenchian Grouping的技术。或者,如果您能够使用 XSLT 2.0,您可以使用xsl:for-each-group

于 2013-10-13T15:40:35.123 回答