質問

I am using a program to generate a report. The program uses an XSL file to generate a PDF report. I am trying to create a custom XSL file.

In my example, I am trying to only generate a report for items that are 3.5" Floppy OR 5.25" Floppy (separately). In addition to this, I am trying to fit the results in two column per index card - for printing.

I'm not an XSL expert, but I've done a research, and found several possible solutions for what I'm trying to achieve (mainly this question) however the final results are always not what I want them to be - I may have a wrong concept of XSL parts, and I'd appreciate any input/pointers.

Here is a part from the 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>

Here is a part from the XSL I created:

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

The PDF report that is generated by the program is wrong because I also get cells with titles that do not match the filter. Also, sometimes at least one item title is not shown. I tried "reverse engineering" to check whether my variable ($individualFloppies) filter isn't right, but when not using the two column approach I get good results however each in its own row.

It feels as if the following:: is causing the problem but it's just a guess.

I also tried following-sibling::, position() mod 2 = 1 as well as minimizing the filter I have.

If anyone can shed some light and tell me how far I am to what I am trying to achieve and where I am wrong I'd appreciate it very much.

As a first time poster here, I hope I provided all the important information.

EDIT: I wasn't sure how to attach here the PDF files of the desired and the current output so I'll just ASCII it:

From the XML above, the desired output should only be one page:

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

What I get after generating the report are two pages:

PAGE 1:

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

PAGE 2:

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

To put the logic in writing: Since 'Title 1' is only '5.25" Floppy' and 'Title 2' is only '3.5" Floppy' they are the only two that should show up. 'Title 3' is '5.25" Floppy' but also is '3.5" Floppy' so it shouldn't show. 'Title 4' is a 'CD-Rom' so it shouldn't show as a column as well.

Writing this makes me realize that the filter I am using isn't working - odd considering I am using some similar filter on some different aspect and it does work.

I hope these edits are what was expected as "examples" and they clarify the issue more.

役に立ちましたか?

解決

AFAICT, the problem here is with the expression:

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

Although you are in the context of looping over the filtered variable, the following:: axis is evaluated in the context of the source document. Here's a small stylesheet that demonstrates the problem in isolation as well as a possible solution:

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

他のヒント

With the help of michael.hor257k (thanks again!) I managed to add and change the necessary lines of code so it'll generate the report I was aiming for.

Here is the updated code (beginning from where the first change is applied):

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

Pointing out the updated lines:

Line 1: Cleaner and, I believe, better way to filter the data into the variable.

Lines 3-4: Implementing first part of michael.hor257k example

Line 5: Make the loop work only on the odd nodes (not sure my terminology is correct)

Lines 26-35/46-57: Implement the second part from michael.hor257k' example as well as check if the current position is the last one.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top