2

I've been working with producing simple PDFs with XSL-FO in RenderX XEP for a while, but I'm relatively new to the more involved functions of XPath.

I have some XML which looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<report>
    <ticket>
        <size>A</size>
        <department>Dept 1</department>
        <category>Cat 1</category>
        <product>Product 1</product>
    </ticket>
    <ticket>
        <size>A</size>
        <department>Dept 1</department>
        <category>Cat 2</category>
        <product>Product 2</product>
    </ticket>
    <ticket>
        <size>B</size>
        <department>Dept 1</department>
        <category>Cat 2</category>
        <product>Product 3</product>
    </ticket>
    <ticket>
        <size>B</size>
        <department>Dept 1</department>
        <category>Cat 1</category>
        <product>Product 1</product>
    </ticket>
    <ticket>
        <size>C</size>
        <department>Dept 1</department>
        <category>Cat 2</category>
        <product>Product 2</product>
    </ticket>
    <ticket>
        <size>D</size>
        <department>Dept 3</department>
        <category>Cat 1</category>
        <product>Product 4</product>
    </ticket>
    <ticket>
        <size>D</size>
        <department>Dept 1</department>
        <category>Cat 1</category>
        <product>Product 1</product>
    </ticket>
</report>

I need to be able to sort this data into tables into a PDF using XSLT1.0 formatting objects. The desired format being the following:

All tickets of the same size being in separate tables (sorted on the page in alphabetical order), which each list their products, contained within their relevant categories and departments. Example:

Desired Output

I have had a go at implementing Muenchian grouping, but the wrong categories are falling under the departments when using a large XML extract, and I haven't been able to list the relevant products below each category.

My probably rather untidy XSL:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:key name="keySize" match="ticket" use="size" />
    <xsl:key name="keyDepartment" match="ticket" use="concat(size, ' ', department)" />
    <xsl:key name="keyCategory" match="ticket" use="concat(size, ' ', department, ' ', category)" />

    <xsl:template match="/report">
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master master-name="simple" page-height="29.7cm" page-width="21cm" margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
                    <fo:region-body />
                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="simple">
                <fo:flow flow-name="xsl-region-body">

                    <xsl:for-each select="ticket[count(. | key('keySize', size)[1]) = 1]">
                        <xsl:sort select="size" order="ascending" />
                        <fo:block>
                            Size <xsl:value-of select="size" />
                        </fo:block>
                        <fo:block>
                            <xsl:variable name="sizes" select="key('keySize', size)" />
                            <xsl:for-each select="$sizes[generate-id() = generate-id(key('keyDepartment', concat(size, ' ', department))[1])]">
                                <xsl:sort select="department" order="ascending" />

                                <!--TABLES START-->
                                <fo:table-and-caption>
                                    <fo:table border="0.2mm solid black" width="100%">
                                        <fo:table-header>
                                            <fo:table-row>
                                                <fo:table-cell>
                                                    <fo:block font-weight="bold" margin="1mm 0mm 0mm 1mm">
                                                        <xsl:text>Department</xsl:text>
                                                    </fo:block>
                                                </fo:table-cell>
                                                <fo:table-cell>
                                                    <fo:block font-weight="bold" margin="1mm 0mm 0mm 1mm">
                                                        <xsl:value-of select="department" />
                                                    </fo:block>
                                                </fo:table-cell>
                                            </fo:table-row>
                                        </fo:table-header>
                                        <fo:table-body>
                                            <fo:table-cell>
                                                <fo:block margin="1mm 0mm 0mm 1mm" />
                                            </fo:table-cell>
                                        </fo:table-body>
                                    </fo:table>
                                </fo:table-and-caption>

                                <!--BRINGS IN WRONG CATEGORIES-->
                                <xsl:for-each select="$sizes[generate-id() = generate-id(key('keyCategory', concat(size, ' ', department, ' ', category))[1])]">
                                    <xsl:sort select="category" order="ascending" />
                                    <fo:table-and-caption>
                                        <fo:table border="0.2mm solid black" width="100%">
                                            <fo:table-header>
                                                <fo:table-row>
                                                    <fo:table-cell>
                                                        <fo:block font-weight="bold" margin="1mm 0mm 0mm 1mm">
                                                            <xsl:text>Category</xsl:text>
                                                        </fo:block>
                                                    </fo:table-cell>
                                                    <fo:table-cell>
                                                        <fo:block font-weight="bold" margin="1mm 0mm 0mm 1mm">
                                                            <xsl:value-of select="category" />
                                                        </fo:block>
                                                    </fo:table-cell>
                                                </fo:table-row>
                                            </fo:table-header>
                                            <fo:table-body>
                                                <fo:table-row>
                                                    <fo:table-cell>
                                                        <fo:block margin="1mm 0mm 0mm 1mm"><xsl:value-of select="description" /></fo:block>
                                                    </fo:table-cell>
                                                </fo:table-row>

                                                <!--

                                                DESCRIPTIONS GO HERE?

                                                -->
                                            </fo:table-body>
                                        </fo:table>
                                    </fo:table-and-caption>
                                </xsl:for-each>                         
                            </xsl:for-each>                         
                        </fo:block>
                    </xsl:for-each>
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
</xsl:stylesheet>

Any help with bringing in the products would be greatly appreciated.

BoBWidget
  • 23
  • 3

1 Answers1

0

I think the problem is with this line, where you try to iterate over all categories for a department

<xsl:for-each select="$sizes[generate-id() = generate-id(key('keyCategory', concat(size, ' ', department, ' ', category))[1])]">

The problem is the variable sizes contains details on different departments, not just the one you are interested in, leading to duplicates.

Try this instead, to restrict it to the current department

<xsl:variable name="depts" select="key('keyDepartment', concat(size, ' ', department))" />
<xsl:for-each select="$depts[generate-id() = generate-id(key('keyCategory', concat(size, ' ', department, ' ', category))[1])]">
Tim C
  • 70,053
  • 14
  • 74
  • 93
  • That is a big help, thanks! The departments are now just listing their relevant categories. The next trick is to list all of the products relevant to each category. Do I need a new key to perform this or is there a way to use the content of the current group? How would I set up the xsl:for-each for that? – BoBWidget Jun 26 '14 at 09:25
  • Just do an xsl:for-each look over the current key `xsl:for-each select="key('keyCategory', concat(size, ' ', department, ' ', category))/product">` – Tim C Jun 26 '14 at 10:33
  • ...and that's the icing on the cake. That's helped my understanding considerably and helped me solve another issue I had. Thank you very much sir! – BoBWidget Jun 26 '14 at 11:34