XSL:在两列中过滤for-each

时间:2014-01-15 07:18:29

标签: xslt xslt-1.0 xsl-fo

我正在使用程序生成报告。该程序使用XSL文件生成PDF报告。我正在尝试创建自定义XSL文件。

在我的示例中,我尝试仅为3.5“Floppy OR 5.25”Floppy(单独)的项目生成报告。除此之外,我试图将结果拟合为每个索引卡两列 - 用于打印。

我不是XSL专家,但我做了一项研究,并为我想要实现的目标找到了几种可能的解决方案(主要是this question),但最终的结果总是不是我想要的它们是 - 我可能有一个错误的XSL部分概念,我很欣赏任何输入/指针。

以下是XML的一部分:

?xml version="1.0" encoding="UTF-8" ?>
<catalog-objects xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="temp.xsd">
    <software-item>
        <item>Software</item>
        <media-types>
            <storage-medium>
                <name>5.25&quot; Floppy</name>
            </storage-medium>
        </media-types>
        <title>Title 1</title>
    </software-item>
    <software-item>
        <item>Software</item>
        <media-types>
            <storage-medium>
                <name>3.5&quot; Floppy</name>
            </storage-medium>
        </media-types>
        <title>Title 2</title>
    </software-item>
    <software-item>
        <item>Software</item>
        <media-types>
            <storage-medium>
                <name>3.5&quot; Floppy</name>
            </storage-medium>
            <storage-medium>
                <name>5.25&quot; Floppy</name>
            </storage-medium>
        </media-types>
        <title>Title 3</title>
    </software-item>
    <software-item>
        <item>Software</item>
        <media-types>
            <storage-medium>
                <name>CD-Rom</name>
            </storage-medium>
        </media-types>
        <title>Title 4</title>
    </software-item>

以下是我创建的XSL的一部分:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
    exclude-result-prefixes="fo">
    <xsl:import href="../../_stylesheets/pdf_desert.xsl" />
    <xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes" />
    <xsl:param name="versionParam" select="'1.0'" />
    <xsl:template match="/">
        <xsl:param name="size" select="count(catalog-objects/software-item)"/>
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master master-name="Index Card 4X6"
                    page-height="4in" page-width="6in" margin-top="4mm"
                    margin-bottom=".65in" margin-left="4mm" margin-right="4mm">
                    <fo:region-body />
                    <fo:region-after />
                </fo:simple-page-master>
            </fo:layout-master-set>
            <xsl:variable name="individualFloppies" select="catalog-objects/software-item[(contains(media-types, '5.25') and not(contains(media-types, '3.5') or contains(media-types, 'ROM') or contains(media-types, 'Disc') or contains(media-types, 'CD') or contains(media-types, 'DVD') or contains(media-types, 'ray'))) or (contains(media-types, '3.5') and not(contains(media-types, '5.25') or contains(media-types, 'ROM') or contains(media-types, 'Disc') or contains(media-types, 'CD') or contains(media-types, 'DVD') or contains(media-types, 'ray')))]" />
            <xsl:param name="size" select="$individualFloppies"/>
            <xsl:for-each select="$individualFloppies[ceiling($size div 2) &gt;= position()]">
                <fo:page-sequence master-reference="Index Card 4X6">
                    <fo:static-content flow-name="xsl-region-after">
                        <fo:block font-size="{$fontSize}">
                        </fo:block>
                    </fo:static-content>

                    <fo:flow flow-name="xsl-region-body">
                        <fo:block font-size="{$fontSize}">
                            <fo:table table-layout="fixed" width="100%" border-collapse="collapse">
                                <fo:table-column column-width="45%" />
                                <fo:table-column column-width="45%" />
                                <fo:table-body>
                                        <fo:table-row>
                                            <fo:table-cell>
                                                    <fo:block text-align="right" font-size="8"><fo:inline font-weight="bold">ID </fo:inline><xsl:value-of select='format-number(archive-id, "000000")' /></fo:block>
                                            </fo:table-cell>
                                            <fo:table-cell>
                                                    <fo:block text-align="right" font-size="8"><fo:inline font-weight="bold">ID </fo:inline><xsl:value-of select='format-number(following::software-item[ceiling($size div 2)]/archive-id, "000000")' /></fo:block>
                                            </fo:table-cell>
                                        </fo:table-row>
                                        <fo:table-row>
                                            <fo:table-cell border-bottom="1px solid #000000">
                                                <fo:block text-align="center" padding-top="0.2in" font-size="12" font-weight="bold">
                                                    <xsl:value-of select="title" />
                                                </fo:block>
                                            </fo:table-cell>
                                            <fo:table-cell border-bottom="1px solid #000000">
                                                <fo:block text-align="center" padding-top="0.2in" font-size="12" font-weight="bold">
                                                    <xsl:value-of select="following::software-item[ceiling($size div 2)]/title" />
                                                </fo:block>
                                            </fo:table-cell>
                                        </fo:table-row>

程序生成的PDF报告是错误的,因为我还会获得标题与过滤器不匹配的单元格。此外,有时至少一个项目标题未显示。 我尝试“逆向工程”来检查我的变量($individualFloppies)过滤器是否正确,但是当不使用两列方法时,我得到了很好的结果,但每个都在它自己的行中。

感觉好像following::引起了问题,但这只是猜测。

我还尝试了following-sibling::position() mod 2 = 1以及最小化我的过滤器。

如果有人能说清楚,并告诉我,我想要实现的目标和我错在哪里,我会非常感激。

作为此处的第一次海报,我希望我提供了所有重要信息。

修改 我不知道如何在这里附加所需和当前输出的PDF文件,所以我只是ASCII它:

从上面的XML中,所需的输出应该只有一页:

  ╔════════════╤════════════╗
  ║   Title 1  │   Title 2  ║
  ╠════════════╪════════════╣
  ║            │            ║
  ║            │            ║
  ║            │            ║
  ╚════════════╧════════════╝

生成报告后我得到的是两页:


PAGE 1:

  ╔════════════╤════════════╗
  ║   Title 1  │   Title 3  ║
  ╠════════════╪════════════╣
  ║            │            ║
  ║            │            ║
  ║            │            ║
  ╚════════════╧════════════╝

PAGE 2:

  ╔════════════╤════════════╗
  ║   Title 2  │   Title 4  ║
  ╠════════════╪════════════╣
  ║            │            ║
  ║            │            ║
  ║            │            ║
  ╚════════════╧════════════╝

将逻辑写入: 由于'Title 1'仅为'5.25'Floppy'而'Title 2'仅为'3.5'Floppy',因此它们是唯一应该出现的两个。 'Title 3'是'5.25'Floppy',但也是'3.5“Floppy'所以它不应该显示。 '标题4'是'CD-Rom',因此它也不应该显示为列。

写这个让我意识到我正在使用的过滤器不起作用 - 奇怪的是我在某些不同的方面使用了一些类似的过滤器并且确实有效。

我希望这些编辑是预期的“示例”,他们会更多地澄清这个问题。

2 个答案:

答案 0 :(得分:1)

AFAICT,这里的问题是表达式:

<xsl:value-of select="following::software-item[ceiling($size div 2)]/title" />

虽然您处于循环过滤变量的上下文中,但following::轴在源文档的上下文中进行评估。这是一个小样式表,可以单独演示问题以及可能的解决方案:

<?xml version="1.0" encoding="utf-8"?>
<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:template match="/">

<xsl:variable name="individualFloppies" select="catalog-objects/software-item[(contains(media-types, '5.25') and not(contains(media-types, '3.5') or contains(media-types, 'ROM') or contains(media-types, 'Disc') or contains(media-types, 'CD') or contains(media-types, 'DVD') or contains(media-types, 'ray'))) or (contains(media-types, '3.5') and not(contains(media-types, '5.25') or contains(media-types, 'ROM') or contains(media-types, 'Disc') or contains(media-types, 'CD') or contains(media-types, 'DVD') or contains(media-types, 'ray')))]" />
<out>
    <wrong>
        <xsl:for-each select="$individualFloppies">
            <pair>
                <left><xsl:value-of select="title" /></left>
                <right><xsl:value-of select="following::software-item[1]/title"/></right>
            </pair>
        </xsl:for-each>
    </wrong>
    <right>
        <xsl:for-each select="$individualFloppies">
            <xsl:variable name="pos" select="position()" />
            <pair>
                <left><xsl:value-of select="title" /></left>
                <right><xsl:value-of select="$individualFloppies[$pos+1]/title"/></right>
            </pair>
        </xsl:for-each>
    </right>
</out>
</xsl:template>
</xsl:stylesheet>

答案 1 :(得分:0)

在michael.hor257k的帮助下(再次感谢!)我设法添加并更改了必要的代码行,以便生成我的目标报告。

以下是更新的代码(从应用第一次更改的位置开始):

            <xsl:variable name="individualFloppies" select="catalog-objects/software-item[normalize-space(media-types)='3.5&quot; Floppy' or normalize-space(media-types)='5.25&quot; Floppy']" />
            <xsl:param name="size" select="$individualFloppies"/>
            <xsl:for-each select="$individualFloppies">
            <xsl:variable name="pos" select="position()" />
                <xsl:if test="position() mod 2 = 1">
                    <fo:page-sequence master-reference="Index Card 4X6">
                        <fo:static-content flow-name="xsl-region-after">
                            <fo:block font-size="{$fontSize}">
                            </fo:block>
                        </fo:static-content>
    <!--Table Begins-->
                        <fo:flow flow-name="xsl-region-body">
                            <fo:block font-size="{$fontSize}">
                                <fo:table table-layout="fixed" width="100%" border-collapse="collapse">
                                    <fo:table-column column-width="2.5%" />
                                    <fo:table-column column-width="45%" />
                                    <fo:table-column column-width="2.5%" />
                                    <fo:table-column column-width="2.5%" />
                                    <fo:table-column column-width="45%" />
                                    <fo:table-column column-width="2.5%" />
                                    <fo:table-body>
                                            <fo:table-row>
                                                <fo:table-cell number-columns-spanned="3">
                                                        <fo:block text-align="right" font-size="8"><fo:inline font-weight="bold">ID </fo:inline><xsl:value-of select='format-number(archive-id, "000000")' /></fo:block>
                                                </fo:table-cell>
                                                <xsl:choose>
                                                    <xsl:when test="position() != last()">
                                                        <fo:table-cell number-columns-spanned="3">
                                                            <fo:block text-align="right" font-size="8"><fo:inline font-weight="bold">ID </fo:inline><xsl:value-of select='format-number($individualFloppies[$pos+1]/archive-id, "000000")' /></fo:block>
                                                        </fo:table-cell>
                                                    </xsl:when>
                                                <xsl:otherwise>
                                                    <fo:table-cell number-columns-spanned="3"><fo:block></fo:block></fo:table-cell>
                                                </xsl:otherwise>
                                            </xsl:choose>
                                            </fo:table-row>
                                            <fo:table-row>
                                                <fo:table-cell><fo:block></fo:block></fo:table-cell>
                                                <fo:table-cell border-bottom="1px solid #000000">
                                                    <fo:block text-align="center" padding-top="0.2in" font-size="12" font-weight="bold">
                                                        <xsl:value-of select="title" />
                                                    </fo:block>
                                                </fo:table-cell>
                                                <fo:table-cell><fo:block></fo:block></fo:table-cell>
                                                <fo:table-cell><fo:block></fo:block></fo:table-cell>
                                                <xsl:choose>
                                                    <xsl:when test="position() != last()">
                                                        <fo:table-cell border-bottom="1px solid #000000">
                                                            <fo:block text-align="center" padding-top="0.2in" font-size="12" font-weight="bold">
                                                                <xsl:value-of select="$individualFloppies[$pos+1]/title" />
                                                            </fo:block>
                                                        </fo:table-cell>
                                                    </xsl:when>
                                                    <xsl:otherwise>
                                                        <fo:table-cell><fo:block></fo:block></fo:table-cell>
                                                    </xsl:otherwise>
                                                </xsl:choose>
                                                <fo:table-cell><fo:block></fo:block></fo:table-cell>
                                            </fo:table-row>

指出更新的行:

第1行:更清洁,我相信,更好的方法是将数据过滤到变量中。

第3-4行:实施michael.hor257k示例的第一部分

第5行:使循环仅在奇数节点上工作(不确定我的术语是否正确)

第26-35 / 46-57行:从michael.hor257k'示例中实现第二部分,并检查当前位置是否是最后一个。