A common requirement is to construct a so-called Crosstab, in which multiple attributes are incorporated in a single table. For example, this data represents sets of trousers, with waist, length and price elements.
XML Data:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <group> <record> <Product name="Yummy-Yeans" ArtNo="102" Beschreibung="für Damen" /> <Langtext>Diese Yeans sprengt alle Grenzen des bisher Gekannten.</Langtext> <Merkmale> <Merkmal waist="28" length="30" price="129" /> <Merkmal waist="28" length="32" price="132" /> <Merkmal waist="28" length="34" price="134" /> <Merkmal waist="28" length="36" price="133" /> <Merkmal waist="28" length="38" price="133" /> <Merkmal waist="28" length="40" price="138" /> <Merkmal waist="28" length="42" price="140" /> <Merkmal waist="28" length="44" price="138" /> <Merkmal waist="30" length="32" price="139" /> <Merkmal waist="30" length="33" price="145" /> <Merkmal waist="30" length="34" price="152" /> <Merkmal waist="30" length="36" price="142" /> <Merkmal waist="30" length="38" price="144" /> <Merkmal waist="30" length="40" price="146" /> <Merkmal waist="30" length="42" price="147" /> <Merkmal waist="30" length="44" price="149" /> <Merkmal waist="32" length="28" price="150" /> <Merkmal waist="32" length="30" price="148" /> <Merkmal waist="32" length="32" price="152" /> <Merkmal waist="32" length="34" price="147" /> <Merkmal waist="32" length="36" price="153" /> <Merkmal waist="32" length="38" price="149" /> <Merkmal waist="32" length="40" price="148" /> <Merkmal waist="32" length="42" price="160" /> </Merkmale> </record> <record> <Product name="Yummy-Yeans" ArtNo="103" Beschreibung="für Herren" /> <Langtext>Diese Yeans sprengt alle Grenzen des bisher Gekannten.</Langtext> <Merkmale> <Merkmal waist="28" length="30" price="29" /> <Merkmal waist="28" length="32" price="32" /> <Merkmal waist="28" length="34" price="34" /> <Merkmal waist="28" length="36" price="33" /> <Merkmal waist="28" length="32" price="33" /> <Merkmal waist="28" length="34" price="38" /> <Merkmal waist="28" length="36" price="40" /> <Merkmal waist="28" length="38" price="38" /> <Merkmal waist="30" length="32" price="39" /> <Merkmal waist="30" length="33" price="45" /> <Merkmal waist="30" length="34" price="52" /> <Merkmal waist="30" length="36" price="42" /> <Merkmal waist="30" length="38" price="44" /> <Merkmal waist="30" length="40" price="46" /> <Merkmal waist="30" length="42" price="47" /> <Merkmal waist="30" length="44" price="49" /> <Merkmal waist="32" length="28" price="50" /> <Merkmal waist="32" length="30" price="48" /> <Merkmal waist="32" length="32" price="52" /> <Merkmal waist="32" length="34" price="47" /> <Merkmal waist="32" length="36" price="53" /> <Merkmal waist="32" length="38" price="49" /> <Merkmal waist="32" length="40" price="48" /> <Merkmal waist="32" length="42" price="60" /> </Merkmale> </record> <record> <Product name="Yummy-Yeans" ArtNo="104" Beschreibung="Unisex" /> <Langtext>Diese Yeans sprengt alle Grenzen des bisher Gekannten.</Langtext> <Merkmale> <Merkmal waist="38" length="32" price="29" /> <Merkmal waist="38" length="33" price="32" /> <Merkmal waist="38" length="34" price="34" /> <Merkmal waist="38" length="36" price="33" /> <Merkmal waist="38" length="35" price="33" /> <Merkmal waist="38" length="34" price="38" /> <Merkmal waist="38" length="36" price="40" /> <Merkmal waist="38" length="38" price="38" /> <Merkmal waist="40" length="32" price="39" /> <Merkmal waist="40" length="33" price="45" /> <Merkmal waist="40" length="34" price="52" /> <Merkmal waist="40" length="36" price="42" /> <Merkmal waist="40" length="40" price="44" /> <Merkmal waist="40" length="40" price="46" /> <Merkmal waist="40" length="42" price="47" /> <Merkmal waist="40" length="44" price="49" /> <Merkmal waist="42" length="28" price="50" /> <Merkmal waist="42" length="30" price="48" /> <Merkmal waist="42" length="42" price="52" /> <Merkmal waist="42" length="34" price="47" /> <Merkmal waist="42" length="36" price="53" /> <Merkmal waist="42" length="38" price="49" /> <Merkmal waist="42" length="40" price="48" /> <Merkmal waist="42" length="42" price="60" /> </Merkmale> </record> </group> |
The target layout involves a table with the distinct lengths horizontally, distinct waist sizes vertically and prices in each cell.
This can be achieved with the following steps:
- Create a data source with <record> as a record node, then defining a field to contain the entire XML tree of the <Merkmale> node. Marking it as an “XML fragment” will do this.
- Set up a Formatting Rule, consisting of a standard InDesign table with table header row, one body row, a footer row and as many columns as needed, for example 20 columns.
- Use table/cell/paragraph styles to define the appearance of the table. The Formatting Rule could look something like this:
- Configure Table Options from the panel menu, choosing “Complex Table” and entering an XSL transformation which creates the cross table:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:key name="merkmal-by-waist" match="Merkmale/Merkmal" use="@waist" /> <xsl:key name="merkmal-by-length" match="Merkmale/Merkmal" use="@length" /> <xsl:template match="/"> <table> <thead> <tr> <td><xsl:text>Länge:</xsl:text></td> <xsl:for-each select="Merkmale/Merkmal[count(. | key('merkmal-by-length', @length)[1]) = 1]"> <xsl:sort select="@length" data-type="number" order="ascending"/> <td><xsl:value-of select="@length"/></td> </xsl:for-each> </tr> </thead> <tbody> <xsl:for-each select="Merkmale/Merkmal[count(. | key('merkmal-by-waist', @waist)[1]) = 1]"> <xsl:sort select="@waist" data-type="number" order="ascending"/> <xsl:variable name="waist" select="@waist"></xsl:variable> <tr> <td>Umfang: <xsl:value-of select="@waist"/></td> <xsl:for-each select="../Merkmal[count(. | key('merkmal-by-length', @length)[1]) = 1]"> <xsl:sort select="@length" data-type="number" order="ascending"/> <td> <xsl:choose> <xsl:when test="normalize-space(key('merkmal-by-length', @length)[@waist = $waist]/@price)"> <xsl:value-of select="key('merkmal-by-length', @length)[@waist = $waist]/@price"/> <xsl:text> €</xsl:text> </xsl:when> <xsl:otherwise><xsl:text>–</xsl:text></xsl:otherwise> </xsl:choose> </td> </xsl:for-each> </tr> </xsl:for-each> </tbody> <tfoot> <tr> <td><xsl:text>Alle Preise verstehen sich zuzüglich der gesetzlichen USt. Preis nur für Wiederverkäufer.</xsl:text></td> </tr> </tfoot> </table> </xsl:template> </xsl:stylesheet> |
- Placing the cursor into a text frame, choosing “Paginate” and … well, here’s what it looks like:
Data shown in this example can be downloaded from by clicking this link
Many thanks for the help of Rudi Warttmann at TopSet for his help with this example