Complex Grouping using XSLT 1.0

前端 未结 2 1287
无人共我
无人共我 2021-01-28 08:13

I\'ve revised the data file and added a Grouping column. I could not figure out a logic for grouping otherwise.

The data contains information for a stamp collection.

相关标签:
2条回答
  • 2021-01-28 08:34

    If you want to have only unique Scott values within each Group, and only unique Minor values within each Scott subgroup, then yes, you will need three keys.

    And if the values by which you want to subgroup are not unique to each parent group, then the keys will have to be concatenated in order to narrow the key down to matching items from the current parent group only.

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:key name="stamp-by-group" match="stamp" use="Group" />
    <xsl:key name="stamp-by-scott" match="stamp" use="concat(Group, '|', Scott)" />
    <xsl:key name="stamp-by-minor" match="stamp" use="concat(Group, '|', Scott, '|', Minor)" />
    
    <xsl:template match="/stamps">
        <xsl:copy>
            <xsl:for-each select="stamp[count(. | key('stamp-by-group', Group)[1]) = 1]">
                <StampGroup id="{Group}">
                    <xsl:for-each select="key('stamp-by-group', Group)[count(. | key('stamp-by-scott', concat(Group, '|', Scott))[1]) = 1]">
                        <xsl:apply-templates select="key('stamp-by-scott', concat(Group, '|', Scott))[count(. | key('stamp-by-minor', concat(Group, '|', Scott, '|', Minor))[1]) = 1]"/>
                    </xsl:for-each>
                </StampGroup>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="stamp">
        <xsl:copy>
            <xsl:copy-of select="Scott | Title"/>
            <Minor><xsl:value-of select="Minor" /></Minor>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    Edit:

    If you're not creating anything for the group by Scott, then you can skip the secondary grouping and its associated key, and go directly to the tertiary grouping:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:key name="stamp-by-group" match="stamp" use="Group" />
    <xsl:key name="stamp-by-minor" match="stamp" use="concat(Group, '|', Scott, '|', Minor)" />
    
    <xsl:template match="/stamps">
        <xsl:copy>
            <xsl:for-each select="stamp[count(. | key('stamp-by-group', Group)[1]) = 1]">
                <StampGroup id="{Group}">
                    <xsl:apply-templates select="key('stamp-by-group', Group)[count(. | key('stamp-by-minor', concat(Group, '|', Scott, '|', Minor))[1]) = 1]"/>
                </StampGroup>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="stamp">
        <xsl:copy>
            <xsl:copy-of select="Scott | Title"/>
            <Minor><xsl:value-of select="Minor" /></Minor>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    
    0 讨论(0)
  • 2021-01-28 08:46

    Your problem is interesting. Basic order is ItemNo with grouping header on change, but in case of groups in Series or Issue there shall be another grouping header without changing the ItemNo order. I figured out the following and used a html table with background color for the grouping headers for easier overview. I didn't completely understand the expected output, I'm not a stamp expert. The script should give you the idea how to solve that.

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:key name="ItemNo" match="stamp" use="ItemNo" />
        <xsl:key name="Series" match="stamp" use="Series" />
        <xsl:key name="Issue" match="stamp" use="Issue" />
        <xsl:template match="/">
            <table border="1">
                <xsl:apply-templates select="stamps/stamp[generate-id(.)=generate-id(key('ItemNo',ItemNo)[1])]" mode="groupItem">
                    <xsl:sort select="ItemNo"/>
                </xsl:apply-templates>
            </table>
        </xsl:template>
        <xsl:template match="stamp" mode="groupItem">
            <xsl:variable name="varItemNo" select="ItemNo"/>
            <xsl:apply-templates select="../stamp[ItemNo=$varItemNo][generate-id(.)=generate-id(key('Series',Series)[1])]" mode="groupSeries">
                <xsl:sort select="ItemNo"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="../stamp[ItemNo=$varItemNo][generate-id(.)=generate-id(key('Issue',Issue)[1])]" mode="groupIssue">
                <xsl:sort select="Issue"/>
            </xsl:apply-templates>
            <tr style="background-color:yellow">
                <td><xsl:value-of select="ItemNo"/></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
            <xsl:apply-templates select="../stamp[ItemNo=$varItemNo]">
                <xsl:sort select="Series"/>
                <xsl:sort select="Issue"/>
                <xsl:sort select="Minor"/>
            </xsl:apply-templates>
        </xsl:template>
        <xsl:template match="stamp" mode="groupSeries">
            <tr style="background-color:gold">
                <td></td>
                <td></td>
                <td><xsl:value-of select="Series"/></td>
                <td></td>
                <td></td>
                <td></td>
            </tr>
        </xsl:template>
        <xsl:template match="stamp" mode="groupIssue">
            <tr style="background-color:tan">
                <td></td>
                <td></td>
                <td></td>
                <td></td>
                <td><xsl:value-of select="Issue"/></td>
                <td></td>
            </tr>
        </xsl:template>
        <xsl:template match="stamp">
            <tr>
                <td><xsl:value-of select="ItemNo"/></td>
                <td><xsl:value-of select="Date"/></td>
                <td><xsl:value-of select="Series"/></td>
                <td><xsl:value-of select="Name"/></td>
                <td><xsl:value-of select="Issue"/></td>
                <td><xsl:value-of select="Minor"/></td>
            </tr>
        </xsl:template>
    </xsl:stylesheet>
    

    ... and yes, the html isn't complete

    0 讨论(0)
提交回复
热议问题