简体   繁体   English

使用XSLT 1.0进行复杂分组

[英]Complex Grouping using XSLT 1.0

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. 数据包含集邮的信息。

Here is sample XML: 这是示例XML:

<?xml version="1.0" encoding="UTF-8"?>
<stamps>        
<stamp>     
<Group>25</Group>       
<Scott>3133</Scott>     
<Title>32¢ Thornton Wilder</Title>      
<Series>Literary Arts</Series>      
</stamp>        
<stamp>     
<Group>26</Group>       
<Scott>3134</Scott>     
<Title>32¢ Charlie Chaplin</Title>      
</stamp>
<stamp>     
<Group>26</Group>       
<Scott>3135</Scott>     
<Title>32¢ Raoul Wallenberg</Title>     
</stamp>
<stamp>     
<Group>27</Group>       
<Scott>3136</Scott>     
<Title>Sheet of 15</Title>      
<Issue>The World of Dinosaurs</Issue>       
</stamp>        
<stamp>     
<Group>27</Group>       
<Scott>3136</Scott>     
<Minor>a</Minor>        
<Title>32¢ Ceratosaurus</Title>     
<Issue>The World of Dinosaurs</Issue>       
</stamp>        
<stamp>     
<Group>27</Group>       
<Scott>3136</Scott>     
<Minor>b</Minor>        
<Title>32¢ Camptosaurus</Title>     
<Issue>The World of Dinosaurs</Issue>       
</stamp>        
<stamp>     
<Group>27</Group>       
<Scott>3136</Scott>     
<Minor>c</Minor>        
<Title>32¢ Camarasaurus</Title>     
<Issue>The World of Dinosaurs</Issue>       
</stamp></stamps>

Here is the XSLT I put together: 这是我放在一起的XSLT:

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

<xsl:key name="StampGroup" match="stamp" use="Group"/>
<xsl:key name="ScottGroup" match="stamp" use="concat(Group, '|', Scott)"/>

<xsl:template match="/*">
 <xsl:copy>
  <xsl:apply-templates select="stamp[generate-id() = generate-id(key('StampGroup', Group)[1])]" mode="StampGroup" />
 </xsl:copy>
 </xsl:template>

<xsl:template match="stamp" mode="StampGroup">
<StampGroup id="{Group}">        

<xsl:apply-templates select="key('StampGroup', Group)[generate-id() = generate-id(key('ScottGroup', concat(Group, '|', Scott))[1])]" mode="ScottGroup" />
</StampGroup>
</xsl:template>

<xsl:template match="stamp" mode="ScottGroup">
 <stamp>
  <Scott><xsl:value-of select="Scott"/></Scott>
  <Title><xsl:value-of select="Title"/></Title>
  <Minor><xsl:value-of select="Minor"/></Minor> 
 </stamp>
</xsl:template>

</xsl:stylesheet>

Here is the resulting XML: 这是生成的XML:

<?xml version="1.0" encoding="utf-8"?>
<stamps>
<StampGroup id="25">
  <stamp>
     <Scott>3133</Scott>
     <Title>32¢ Thornton Wilder</Title>
     <Minor/>
  </stamp>
</StampGroup>
<StampGroup id="26">
  <stamp>
     <Scott>3134</Scott>
     <Title>32¢ Charlie Chaplin</Title>
     <Minor/>
  </stamp>
  <stamp>
     <Scott>3135</Scott>
     <Title>32¢ Raoul Wallenberg</Title>
     <Minor/>
   </stamp>
  <stamp>
     <Scott>3136</Scott>
     <Title>Sheet of 15</Title>
     <Minor/>
  </stamp>
 </StampGroup>
</stamps>

It's mostly working. 大部分都在工作。 It's pulling the groups. 它正在拉动群体。 It's pulling UNIQUE <Scott> items, but it's not picking up the <Minor> subitems. 它正在拉UNIQUE <Scott>项,但未拾取<Minor>子项。

I've never used this type of XSLT structure before. 我以前从未使用过这种类型的XSLT结构。 How do you get it to repeat items as in for-each? 您如何像在for-for中一样重复项目?

Group 27 has 4 items in it. 第27组中有4个项目。 They all have the same <Scott> number but different <Minor> fields. 它们都具有相同的<Scott>编号,但具有不同的<Minor>字段。

Do I need to create a third key? 我需要创建第三个密钥吗?

Sorry, forgot to add the desired result: 抱歉,忘记添加所需的结果:

<?xml version="1.0" encoding="utf-8"?>
<stamps>
<StampGroup id="25">
  <stamp>
     <Scott>3133</Scott>
     <Title>32¢ Thornton Wilder</Title>
     <Minor/>
  </stamp>
</StampGroup>
<StampGroup id="26">
  <stamp>
     <Scott>3134</Scott>
     <Title>32¢ Charlie Chaplin</Title>
     <Minor/>
  </stamp>
  <stamp>
     <Scott>3135</Scott>
     <Title>32¢ Raoul Wallenberg</Title>
     <Minor/>
  </stamp>
</StampGroup>
<StampGroup id="27">
  <stamp>
     <Scott>3136</Scott>
     <Title>Sheet of 15</Title>
     <Minor/>
  </stamp>
  <stamp>
     <Scott>3136</Scott>
     <Title>32¢ Ceratosaurus</Title>
     <Minor>a</Minor>       
  </stamp>
  <stamp>
     <Scott>3136</Scott>
     <Title>32¢ Camptosaurus</Title>    
     <Minor>b</Minor>       
  </stamp>
  <stamp>
     <Scott>3136</Scott>
     <Title>32¢ Camarasaurus</Title>
     <Minor>c</Minor>       
  </stamp>
 </StampGroup>
</stamps>

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. 基本顺序是ItemNo,更改时带有分组头,但是如果系列或Issue中有组,则应该有另一个分组头,而不更改ItemNo顺序。 I figured out the following and used a html table with background color for the grouping headers for easier overview. 我弄清楚了以下内容,并使用带有背景颜色的html表作为分组标题,以便于概述。 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 ...是的,HTML不完整

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. 如果要在每个Group只有唯一的Scott值,而在每个Scott子组中只有唯一的Minor值,那么是的,您将需要三个键。

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 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: 如果您没有通过Scott为该分组创建任何内容,则可以跳过第二分组及其关联的键,然后直接转到第三分组:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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