【问题标题】:XSLT beginner: Group XML based on unique element value XSLT 1.0XSLT 初学者:基于唯一元素值 XSLT 1.0 对 XML 进行分组
【发布时间】:2020-02-02 11:56:11
【问题描述】:

我是初学者,我正在尝试使用 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>

【问题讨论】:

  • 如果你想对分组的元素进行分组和包装,那么显然你的包装器(例如data)需要在&lt;xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyCategory', category)[1])]"&gt;内部使用,例如&lt;xsl:for-each select="//Row[generate-id(.) = generate-id(key('keyCategory', category)[1])]"&gt;&lt;data&gt;...&lt;/data&gt;&lt;/xsl:for-each&gt;。如果您还想识别每个组中的唯一位置,那么您需要第二个密钥或一些特定于处理器的扩展方法。
  • @MartinHonnen 非常感谢,现在按照您的建议工作。

标签: xml xslt xslt-1.0 xslt-grouping


【解决方案1】:

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

<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

【讨论】:

  • 是否可以在新行上显示每个位置?这 将位置显示在一行中,难以阅读?
  • 由于&lt;xsl:output indent="yes"/&gt;,输出(包括任何locations)在xsltfiddle.liberty-development.net/94Acsm4/1 对我来说很好地缩进。你用的是哪个 XSLT 处理器,你是怎么运行的,当你看到所有locations 在一行时,你怎么看转换结果?
  • 这是我的错误,我忘了添加, 现在它工作得很好 :) 非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-25
  • 2023-02-10
  • 1970-01-01
相关资源
最近更新 更多