使用 XSLT 1.0 的复杂分组
Complex Grouping using XSLT 1.0
我修改了数据文件并添加了分组列。否则我想不出分组的逻辑。
数据包含集邮信息。
这是示例 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>
这是我整理的 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>
这是结果 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>
大部分时间都在工作。它正在拉动群体。它正在提取唯一的 <Scott>
个项目,但没有提取 <Minor>
个子项目。
我以前从未使用过这种类型的 XSLT 结构。你如何让它像 for-each 一样重复项目?
第 27 组有 4 个项目。它们都具有相同的 <Scott>
编号但不同的 <Minor>
字段。
我需要创建第三个密钥吗?
抱歉,忘记添加想要的结果:
<?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>
你的问题很有趣。基本顺序是 ItemNo,在更改时分组 header,但如果是 Series 或 Issue 中的组,则应在不更改 ItemNo 顺序的情况下进行另一个分组 header。我想出了以下内容,并使用 html table 和分组 header 的背景颜色,以便于查看。我没有完全理解预期的输出,我不是邮票专家。该脚本应该让您了解如何解决该问题。
<?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>
...是的,html 不完整
如果您希望每个 Group
中只有唯一的 Scott
值,并且每个 Scott
子组中只有唯一的 Minor
值,那么是的,您将需要三把钥匙。
并且如果您要分组的值对于每个父组不是唯一的,则必须连接键以将键缩小到仅来自当前父组的匹配项。
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>
编辑:
如果您没有为 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>
我修改了数据文件并添加了分组列。否则我想不出分组的逻辑。
数据包含集邮信息。
这是示例 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>
这是我整理的 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>
这是结果 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>
大部分时间都在工作。它正在拉动群体。它正在提取唯一的 <Scott>
个项目,但没有提取 <Minor>
个子项目。
我以前从未使用过这种类型的 XSLT 结构。你如何让它像 for-each 一样重复项目?
第 27 组有 4 个项目。它们都具有相同的 <Scott>
编号但不同的 <Minor>
字段。
我需要创建第三个密钥吗?
抱歉,忘记添加想要的结果:
<?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>
你的问题很有趣。基本顺序是 ItemNo,在更改时分组 header,但如果是 Series 或 Issue 中的组,则应在不更改 ItemNo 顺序的情况下进行另一个分组 header。我想出了以下内容,并使用 html table 和分组 header 的背景颜色,以便于查看。我没有完全理解预期的输出,我不是邮票专家。该脚本应该让您了解如何解决该问题。
<?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>
...是的,html 不完整
如果您希望每个 Group
中只有唯一的 Scott
值,并且每个 Scott
子组中只有唯一的 Minor
值,那么是的,您将需要三把钥匙。
并且如果您要分组的值对于每个父组不是唯一的,则必须连接键以将键缩小到仅来自当前父组的匹配项。
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>
编辑:
如果您没有为 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>