在xslt v2.0中重置计数器

时间:2017-08-23 09:47:19

标签: xslt xslt-2.0

考虑我的XML文件:

<Data>
  <VetaP dfg="2" ppp="oe"/>
  <VetaD ods="3" ds="oda"/>
  <VetaR date="080817"/>
  <VetaR date=""/>
  <VetaR date=""/>
  <VetaR date=""/>
  <VetaR date="080817"/>
  <VetaR date=""/>
  <VetaR date=""/>
  <VetaR date="080817"/>
</Data>

我需要在<VetaR>中添加属性seq,此属性是每个创建的VetaR的计数器。但是,我需要每隔5次<VetaR>重置计数器。我还需要添加一个属性cnt,其中,它也是一个计数器,但这次它只会在<VetaR>的每5次出现时递增。我还需要删除空属性。

这是我的XSLT代码:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Data">
    <xsl:copy>
        <xsl:for-each-group select="*" group-adjacent="(position() - 1) idiv 5">
            <xsl:apply-templates select="current-group()">
                <xsl:with-param name="group-pos" select="position()"/>
            </xsl:apply-templates>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

<xsl:template match="VetaR">
    <xsl:param name="group-pos"/>
    <VetaR seq="{position()}" cnt="{$group-pos}">
        <xsl:apply-templates select="@*"/>
    </VetaR>
</xsl:template>

<xsl:template match="VetaR/@*[not(normalize-space())]"/>

当前输出:

<Data>
  <VetaP dfg="2" ppp="oe"/>
  <VetaD ods="3" ds="oda"/>
  <VetaR seq="3" cnt="1" date="080817"/>
  <VetaR seq="4" cnt="1"/>
  <VetaR seq="5" cnt="1"/>
  <VetaR seq="1" cnt="2"/>
  <VetaR seq="2" cnt="2" date="080817"/>
  <VetaR seq="3" cnt="2"/>
  <VetaR seq="4" cnt="2"/>
  <VetaR seq="5" cnt="2" date="080817"/></Data>

期望的输出:

  <Data>
  <VetaP dfg="2" ppp="oe"/>
  <VetaD ods="3" ds="oda"/>
  <VetaR seq="1" cnt="1" date="080817"/>
  <VetaR seq="2" cnt="1"/>
  <VetaR seq="3" cnt="1"/>
  <VetaR seq="4" cnt="1"/>
  <VetaR seq="5" cnt="1" date="080817"/>
  <VetaR seq="1" cnt="2"/>
  <VetaR seq="2" cnt="2"/>
  <VetaR seq="3" cnt="2" date="080817"/></Data>

2 个答案:

答案 0 :(得分:2)

为什么不简单:

<xsl:template match="VetaR">
    <VetaR seq="{(position() - 1)  mod 5 + 1}" cnt="{(position() - 1) idiv 5 + 1}">
        <xsl:if test="string(@date)">
            <xsl:copy-of select="@date"/>
        </xsl:if>
     </VetaR>
</xsl:template>

答案 1 :(得分:2)

我会把它解决为位置分组:

<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:output indent="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Data">
        <xsl:copy>
            <xsl:for-each-group select="*" group-adjacent="(position() - 1) idiv 5">
                <xsl:apply-templates select="current-group()">
                    <xsl:with-param name="group-pos" select="position()"/>
                </xsl:apply-templates>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="VetaR">
        <xsl:param name="group-pos"/>
        <VetaR seq="{position()}" cnt="{$group-pos}">
            <xsl:apply-templates select="@*"/>
        </VetaR>
    </xsl:template>

    <xsl:template match="VetaR/@*[not(normalize-space())]"/>
</xsl:stylesheet>