XSLT基于值的有效序列

时间:2015-03-10 17:53:53

标签: xml xslt xslt-1.0

我需要生成一个有效序列,其中序列号应在每次更改值后重置。例如:

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

2 个答案:

答案 0 :(得分:2)

这是一个分组问题,因此您可以使用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中一起出现。在这种情况下,看起来应该是一个公平的假设。

答案 1 :(得分:-1)

作为替代方法,您可以考虑这样的事情:

<?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元素并计算匹配的前一个兄弟元素的数量。您会发现此解决方案返回与上面的分组解决方案相同的结果,虽然稍微过程密集,但可能会更容易阅读。你可以很容易地改善前面兄弟姐妹表达的数量,但是我把它们的方式保持得更加清晰。