基于值的 XSLT 有效序列
XSLT effective sequence based on values
我需要生成一个有效的序列,其中序列号在每次更改值后都应重置。示例:
<parent>
<child>
<name>A</name>
<date>02/01/2015<date>
</child>
<child>
<name>A</name>
<date>02/05/2015<date>
</child>
<child>
<name>A</name>
<date>02/05/2015<date>
</child>
<child>
<name>A</name>
<date>02/10/2015<date>
</child>
<child>
<name>A</name>
<date>02/10/2015<date>
</child>
<child>
<name>B</name>
<date>02/01/2015<date>
</child>
<child>
<name>B</name>
<date>02/05/2015<date>
</child>
</parent>
应给出以下序列结果(即每次名称和日期的组合发生变化时,序列应重置为 0,并且对于每个相同的连续值,应递增序列号):
<parent>
<child>
<name>A</name>
<date>02/01/2015<date>
<sequence>0</sequence>
</child>
<child>
<name>A</name>
<date>02/05/2015<date>
<sequence>0</sequence>
</child>
<child>
<name>A</name>
<date>02/05/2015<date>
<sequence>1</sequence>
</child>
<child>
<name>A</name>
<date>02/10/2015<date>
<sequence>0</sequence>
</child>
<child>
<name>A</name>
<date>02/10/2015<date>
<sequence>1</sequence>
</child>
<child>
<name>B</name>
<date>02/01/2015<date>
<sequence>0</sequence>
</child>
<child>
<name>B</name>
<date>02/05/2015<date>
<sequence>0</sequence>
</child>
</parent>
这是一个分组问题,因此您可以为此使用 Muenchian 分组:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kSequence" match="child" use="concat(name, '+', date)"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates
select="child[generate-id() =
generate-id(key('kSequence', concat(name, '+', date))[1])]"
mode="group" />
</xsl:copy>
</xsl:template>
<xsl:template match="child" mode="group">
<xsl:apply-templates select="key('kSequence', concat(name, '+', date))" />
</xsl:template>
<xsl:template match="child">
<xsl:copy>
<xsl:copy-of select="*" />
<sequence>
<xsl:value-of select="position() - 1"/>
</sequence>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当您的示例输入 运行 时,它会产生所需的输出。注意:这假定具有相同名称和日期的项目一起出现在您的输入 XML 中。在这种情况下,这看起来应该是一个合理的假设。
作为替代方法,您可以考虑这样的方法:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="parent">
<xsl:apply-templates select="child">
<xsl:sort select="name"/>
<xsl:sort select="date"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="child">
<xsl:variable name="date" select="date"/>
<xsl:variable name="name" select="name"/>
<child>
<sequence>
<xsl:value-of select="count(preceding-sibling::*[date eq $date][name eq $name])"/>
</sequence>
</child>
</xsl:template>
</xsl:stylesheet>
此解决方案依赖于对 xml 元素进行预排序并计算匹配的前面兄弟姐妹的数量。您会发现此解决方案 returns 与上述分组解决方案的结果相同,虽然过程更加密集,但可能被认为更易于阅读。您可以很容易地提高前面兄弟姐妹表达的数量,但我保留了它们更明确的方式。
我需要生成一个有效的序列,其中序列号在每次更改值后都应重置。示例:
<parent>
<child>
<name>A</name>
<date>02/01/2015<date>
</child>
<child>
<name>A</name>
<date>02/05/2015<date>
</child>
<child>
<name>A</name>
<date>02/05/2015<date>
</child>
<child>
<name>A</name>
<date>02/10/2015<date>
</child>
<child>
<name>A</name>
<date>02/10/2015<date>
</child>
<child>
<name>B</name>
<date>02/01/2015<date>
</child>
<child>
<name>B</name>
<date>02/05/2015<date>
</child>
</parent>
应给出以下序列结果(即每次名称和日期的组合发生变化时,序列应重置为 0,并且对于每个相同的连续值,应递增序列号):
<parent>
<child>
<name>A</name>
<date>02/01/2015<date>
<sequence>0</sequence>
</child>
<child>
<name>A</name>
<date>02/05/2015<date>
<sequence>0</sequence>
</child>
<child>
<name>A</name>
<date>02/05/2015<date>
<sequence>1</sequence>
</child>
<child>
<name>A</name>
<date>02/10/2015<date>
<sequence>0</sequence>
</child>
<child>
<name>A</name>
<date>02/10/2015<date>
<sequence>1</sequence>
</child>
<child>
<name>B</name>
<date>02/01/2015<date>
<sequence>0</sequence>
</child>
<child>
<name>B</name>
<date>02/05/2015<date>
<sequence>0</sequence>
</child>
</parent>
这是一个分组问题,因此您可以为此使用 Muenchian 分组:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kSequence" match="child" use="concat(name, '+', date)"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates
select="child[generate-id() =
generate-id(key('kSequence', concat(name, '+', date))[1])]"
mode="group" />
</xsl:copy>
</xsl:template>
<xsl:template match="child" mode="group">
<xsl:apply-templates select="key('kSequence', concat(name, '+', date))" />
</xsl:template>
<xsl:template match="child">
<xsl:copy>
<xsl:copy-of select="*" />
<sequence>
<xsl:value-of select="position() - 1"/>
</sequence>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当您的示例输入 运行 时,它会产生所需的输出。注意:这假定具有相同名称和日期的项目一起出现在您的输入 XML 中。在这种情况下,这看起来应该是一个合理的假设。
作为替代方法,您可以考虑这样的方法:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="parent">
<xsl:apply-templates select="child">
<xsl:sort select="name"/>
<xsl:sort select="date"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="child">
<xsl:variable name="date" select="date"/>
<xsl:variable name="name" select="name"/>
<child>
<sequence>
<xsl:value-of select="count(preceding-sibling::*[date eq $date][name eq $name])"/>
</sequence>
</child>
</xsl:template>
</xsl:stylesheet>
此解决方案依赖于对 xml 元素进行预排序并计算匹配的前面兄弟姐妹的数量。您会发现此解决方案 returns 与上述分组解决方案的结果相同,虽然过程更加密集,但可能被认为更易于阅读。您可以很容易地提高前面兄弟姐妹表达的数量,但我保留了它们更明确的方式。