Мюнхенская группировка с таблицей XSL-FO

Я некоторое время работал над созданием простых PDF-файлов с помощью XSL-FO в RenderX XEP, но я относительно новичок в более сложных функциях XPath.

У меня есть XML, который выглядит так:

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

Мне нужно иметь возможность сортировать эти данные в таблицы в PDF, используя объекты форматирования XSLT1.0. Желаемый формат следующий:

Все билеты одного размера находятся в отдельных таблицах (отсортированных на странице в алфавитном порядке), в каждой из которых перечислены их продукты, содержащиеся в соответствующих категориях и отделах. Пример:

Желаемый результат

Я попробовал реализовать мюнхенскую группировку, но при использовании большого XML-выборка под отделы попадают неправильные категории, и я не смог перечислить соответствующие продукты под каждой категорией.

Мой, вероятно, довольно неопрятный 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>

Любая помощь с доставкой продуктов будет принята с благодарностью.


person BoBWidget    schedule 25.06.2014    source источник


Ответы (1)


Я думаю, проблема в этой строке, где вы пытаетесь перебрать все категории для отдела.

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

Проблема в том, что переменная sizes содержит сведения о разных отделах, а не только об интересующем вас, что приводит к дублированию.

Вместо этого попробуйте это, чтобы ограничить его текущим отделом

<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])]">
person Tim C    schedule 25.06.2014
comment
Это большая помощь, спасибо! Сейчас отделы просто перечисляют свои соответствующие категории. Следующий трюк — перечислить все продукты, относящиеся к каждой категории. Нужен ли мне для этого новый ключ или есть способ использовать содержимое текущей группы? Как мне настроить для этого xsl:for-each? - person BoBWidget; 26.06.2014
comment
Просто выполните xsl:for-each просмотр текущего ключа xsl:for-each select="key('keyCategory', concat(size, ' ', department, ' ', category))/product"> - person Tim C; 26.06.2014
comment
...и это вишенка на торте. Это значительно помогло моему пониманию и помогло мне решить другую проблему, которая у меня была. Большое спасибо, сэр! - person BoBWidget; 26.06.2014