简体   繁体   中英

XSLT beginner: Group XML based on unique element value XSLT 1.0

I am a beginner and I am trying to group an XML input based on similar category, using XSLT 1.0 Here is the input xml which contains category and location. The out put must group all elements with the same category and list unique locations:

<?xml version="1.0" ?>
<Data>
    <Row>
       <id>123</id>
       <location>/example/games/data.php</location>
       <category>gamedata</category>
    </Row>
    <Row>
        <id>456</id>
       <location>/example/games/data.php</location>
       <category>gamedata</category>
    </Row>
<Row>
        <id>789</id>
       <location>/example/games/score.php</location>
       <category>gamedata</category>
    </Row>
<Row>
       <id>888</id>
       <location>/example/games/title.php</location>
       <category>gametitle</category>
    </Row>
<Row>
        <id>777</id>
       <location>/example/games/title.php</location>
       <category>gametitle</category>
    </Row>
<Row>
        <id>999</id>
       <location>/example/score/title.php</location>
       <category>gametitle</category>
    </Row>
</Data>

Looking for output as(list only unique location grouped by category):

<project>
     <item>
        <data>
<category>gamedata</category>
           <id>456</id>
            <id>789</id>
             <id>123</id>
       <location>/example/games/data.php</location>   
       <location>/example/games/score.php</location>
       </data>
  <data> <category>gametitle</category>
       <id>888</id>
       <id>777</id>
        <id>999</id>
       <location>/example/games/title.php</location>
       <location>/example/score/title.php</location> 
    </data>
</item></project>

What I have tried so far:

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="keyCategory" match="Row" use="category"/>
    <xsl:template match="/">
        <project xmlns="xyz.com">
            <item >
                <name lang="en">Example</name>
                <xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyCategory', category)[1])]">

                    <xsl:for-each select="key('keyCategory', category)">
                          <data>
                            <category><xsl:value-of select="category"/></category>
                            <id><xsl:value-of select="id"/></id>
                             <location><xsl:value-of select="location"/></location></data>
                    </xsl:for-each>
             </xsl:for-each>
</item>
</project>

What I am actually getting:

<project>
     <item>
        <data>
<category>gamedata</category>
           <id>456</id>
       <location>/example/games/data.php</location>

         </data>
         <data>
<category>gamedata</category>
            <id>789</id>
       <location>/example/games/score.php</location>

         </data>
        <data>
<category>gamedata</category>
            <id>789</id>
       <location>/example/games/score.php</location>

         </data>
        <data>
<category>gamedata</category>
       <id>123</id>
       <location>/example/games/data.php</location>

       </data>
  <data>
<category>gametitle</category>
       <id>888</id>
       <location>/example/games/title.php</location>

    </data>
   <data>
<category>gametitle</category>
        <id>777</id>
       <location>/example/games/title.php</location>

    </data>
   <data>
<category>gametitle</category>
        <id>999</id>
       <location>/example/score/title.php</location>

    </data>
</item></project>

For your nested grouping problem I think you want to use a second key:

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>

    <xsl:key name="keyCategory" match="Row" use="category"/>

    <xsl:key name="location" match="Row" use="concat(category, '|', location)"/>

    <xsl:template match="/">
        <project>
            <item>
                <name lang="en">Example</name>
                <xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyCategory', category)[1])]">
                    <data>
                        <xsl:copy-of
                          select="category"/>
                        <xsl:copy-of select="key('keyCategory', category)/id"/>
                        <xsl:copy-of 
                          select="key('keyCategory', category)[generate-id() = generate-id(key('location', concat(category, '|', location))[1])]/location"/>
                    </data>
                </xsl:for-each>
            </item>
        </project>
    </xsl:template>
</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/94Acsm4/0

This only shows the grouping and ignores that your output uses a different namespace, to create the selected elements in the new namespace I would transform them:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns="http://example.com/">
    <xsl:output indent="yes"/>

    <xsl:key name="keyCategory" match="Row" use="category"/>

    <xsl:key name="location" match="Row" use="concat(category, '|', location)"/>

    <xsl:template match="/">
        <project>
            <item>
                <name lang="en">Example</name>
                <xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyCategory', category)[1])]">
                    <data>
                        <xsl:apply-templates
                          select="category"/>
                        <xsl:apply-templates select="key('keyCategory', category)/id"/>
                        <xsl:apply-templates 
                          select="key('keyCategory', category)[generate-id() = generate-id(key('location', concat(category, '|', location))[1])]/location"/>
                    </data>
                </xsl:for-each>
            </item>
        </project>
    </xsl:template>

    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/94Acsm4/1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM