Domanda

After spending a couple of days on trying to find a solution using muenchian grouping I desperately need some help in figuring out the proper xslt code for transforming my XML so that it will produce a unique list of years for all shows (to be imported into Solr eventually). Basically I need the unique grandchildren of a node to be grouped, but somehow all existing solutions on SO did not work for me.

Here's my source XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="http://localhost/default.xsl" ?>
<DIRECTORY>
    <SHOWS>
        <SHOW>
            <TITLE>Child's play</TITLE>
            <EVENTS>
                <EVENT>
                    <YEAR>2014</YEAR>
                    <TITLE>Gala day</TITLE>
                </EVENT>
                <EVENT>
                    <YEAR>2014</YEAR>
                    <TITLE>Gala night</TITLE>
                </EVENT>
                <EVENT>
                    <YEAR>2015</YEAR>
                    <TITLE>Gala night</TITLE>
                </EVENT>
            </EVENTS>
        </SHOW>
    </SHOWS>
</DIRECTORY>

Here's the desired output:

<?xml version="1.0"?>
<add>
  <doc>
    <field name="show_title">Child's play</field>
    <field name="show_year">2014</field>
    <field name="show_year">2015</field>
  </doc>
</add>

Here's my XSLT that does not work and is based on various answers around Stack Overflow

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>

    <xsl:key name="show_key"
             match="TITLE"
             use="TITLE"/>

    <xsl:key name="show_years_key"
             match="TITLE"
             use="concat(TITLE, ' ',
                     EVENTS/EVENT/YEAR)"/>

    <xsl:template match="/">
        <add>
            <xsl:for-each select="/DIRECTORY/SHOWS/SHOW">
                <doc>
                    <xsl:call-template name="show_info"/>
                </doc>
            </xsl:for-each>
        </add>
    </xsl:template>

    <xsl:template name="show_info">
        <field name="show_title">
            <xsl:value-of select="TITLE"/>
        </field>
        <xsl:variable
                name="show_events"
                select="key('show_key', TITLE)"/>
        <xsl:for-each
                select="$show_events[generate-id() =
                             generate-id(
                               key('show_years_key',
                                   concat(TITLE,
                                          ' ',
                                          EVENTS/EVENT/YEAR))[1])]">
            <field name="show_years">
                <xsl:value-of select="EVENTS/EVENT/YEAR"/>
            </field>
        </xsl:for-each>

    </xsl:template>
</xsl:stylesheet>

While I really appreciate any help to get to a working solution I could also use some pointers as to why my solution does not work when it should. I left the minimal example a bit more complex on purpose as I suspect my xslt organization might make things more complicated, but the overall solution works quite well, even with multiple different templates.

È stato utile?

Soluzione

The grouping key needs to match the elements you're trying to group (i.e. the YEAR elements). I'm having a bit of trouble following your call-template logic, I'd approach it more like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>

    <xsl:key name="show_years_key"
             match="YEAR"
             use="concat(ancestor::SHOW[1]/TITLE, ' ', .)"/>

    <xsl:template match="/">
        <add>
            <xsl:apply-templates select="/DIRECTORY/SHOWS/SHOW" />
        </add>
    </xsl:template>

    <xsl:template match="SHOW">
        <doc>
            <field name="show_title">
                <xsl:value-of select="TITLE"/>
            </field>
            <!-- current() here is the SHOW element this template applies to -->
            <xsl:for-each select="EVENTS/EVENT/YEAR[generate-id() = generate-id(
                    key('show_years_key', concat(current()/TITLE, ' ', .))[1])]">
                <field name="show_years">
                    <xsl:value-of select="." />
                </field>
            </xsl:for-each>
        </doc>
    </xsl:template>
</xsl:stylesheet>

The important point is that you're grouping the YEAR elements by the TITLE of their containing SHOW, not the SHOW elements by the YEAR they contain.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top