问题
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:
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.
回答1:
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])]">
来源:https://stackoverflow.com/questions/24411173/muenchian-grouping-with-xsl-fo-table