温馨提示:本文翻译自stackoverflow.com,查看原文请点击:其他 - XSLT beginner: Group XML based on unique element value XSLT 1.0
xml xslt xslt-1.0 xslt-grouping

其他 - XSLT初学者:基于唯一元素值XSLT 1.0对XML进行分组

发布于 2020-04-12 10:18:41

我是一个初学者,我正在尝试使用XSLT 1.0根据相似的类别对XML输入进行分组。这是包含类别和位置的输入xml。输出必须将具有相同类别的所有元素分组并列出唯一的位置:

<?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>

寻找输出为(仅列出按类别分组的唯一位置):

<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>

到目前为止我尝试过的是:

 <?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>

我实际上得到的是:

<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>

查看更多

提问者
Aben
被浏览
63
Martin Honnen 2020-02-02 20:16

对于您的嵌套分组问题,我认为您想使用第二个键:

<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

这仅显示分组,并忽略您的输出使用其他名称空间,以便在新名称空间中创建所选元素,我将对其进行转换:

<?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