0

How do I merge multiple XML structures with XSLT 2.0 and XSL-FO by grouping them by their 1st child (-entry) and then sort them from a to z?

In detail from something like this:

<keyword>
    <key-entry>example<key-entry>
    <key-entry>hello</key-entry>
    <key-entry>world</key-entry>
</keyword>

<keyword>
    <key-entry>another example</key-entry>
    <key-entry>with other data</key-entry>
</keyword>

<keyword>
    <key-entry>example</key-entry>
    <key-entry>nice to see you!</key-entry>
</keyword>

to something like this:

<fo:block>A</fo:block>
<fo:block>another example</fo:block>
    <fo:block>with other data</fo:block>

<fo:block>E</fo:block>
<fo:block>example</fo:block>
    <fo:block>hello</fo:block>
    <fo:block>world</fo:block>
    <fo:block>nice to see you!</fo:block>
garlicDoge
  • 197
  • 1
  • 3
  • 18

1 Answers1

2

Since you're using XSLT 2.0, you can use xsl:for-each-group. See http://www.w3.org/TR/xslt20/#grouping

You need two levels of xsl:for-each-group: one to get the initial letter, and a second to group by the first key-entry in each keyword.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fo="http://www.w3.org/1999/XSL/Format"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:output indent="yes" />

    <xsl:template match="keywords">
      <fo:block>
        <xsl:for-each-group
            select="keyword"
            group-by="upper-case(substring(key-entry[1], 1, 1))">
          <xsl:sort select="current-grouping-key()" />
          <fo:block>
            <xsl:value-of select="current-grouping-key()" />
          </fo:block>
          <xsl:for-each-group
              select="current-group()"
              group-by="key-entry[1]">
            <fo:block>
              <xsl:value-of select="current-grouping-key()" />
            </fo:block>
            <xsl:apply-templates
                select="current-group()/key-entry[position() > 1]" />
          </xsl:for-each-group>
        </xsl:for-each-group>
      </fo:block>
    </xsl:template>

    <xsl:template match="key-entry">
      <fo:block>
        <xsl:apply-templates />
      </fo:block>
    </xsl:template>
</xsl:stylesheet>

produces:

<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">
   <fo:block>A</fo:block>
   <fo:block>another example</fo:block>
   <fo:block>with other data</fo:block>
   <fo:block>E</fo:block>
   <fo:block>example</fo:block>
   <fo:block>hello</fo:block>
   <fo:block>world</fo:block>
   <fo:block>nice to see you!</fo:block>
</fo:block>
Tony Graham
  • 7,306
  • 13
  • 20