XSL递归,如何匹配?

时间:2016-12-19 17:43:39

标签: xslt recursion

我必须进行递归才能添加一些值并返回总数。我有一个XML文件,对于每个coloc_id,我需要返回“montant”里面的内容。例如,对于我下面的XML,我需要返回:

Balthazar : 732
Gaspard : 172 (87+87)
Melchior : 1239 (1236+3) 
Jesus : 104 

我不能使用foreach,这在我的运动中是禁止的。我搜索了3个小时,但我无法弄清楚我需要做什么。下面是我的xsl文件,显示:

Balthazar:732.
Gaspard:87.
Gaspard:87.
Melchior:1236.
Melchior:3.
Jesus:104.

但我想要一个总数,而且我不知道如何在同一时间将几个元素与同一个coloc_id匹配。

<comptes>
	<actions>
		<depense coloc_id="Melchior" categorie="loyer" date="2016-12-12">
			<montant>1236
			</montant>
			<pour coloc_id="Melchior"/>
			<pour coloc_id="Balthazar"/>
		</depense>
		<depense coloc_id="Melchior" categorie="loyer" date="2016-12-12">
			<montant>3
			</montant>
			<pour coloc_id="Melchior"/>
			<pour coloc_id="Balthazar"/>
		</depense>
		<depense coloc_id="Balthazar" categorie="meuble">
			<montant>732
			</montant>
			<pour coloc_id="Gaspard"/>
			<pour coloc_id="Balthazar"/>
		</depense>

		<depense coloc_id="Gaspard" categorie="alimentation">
			<montant>87
			</montant>
			<pour coloc_id="Balthazar"/>
			<pour coloc_id="Gaspard"/>
		</depense>

		<depense coloc_id="Gaspard" categorie="alimentation" >
			<montant>87
			</montant>
			<pour coloc_id="Balthazar"/>
			<pour coloc_id="Gaspard"/>
			<pour coloc_id="Melchior"/>
			<pour coloc_id="Jesus"/>
		</depense>

		<depense coloc_id="Jesus" categorie="alimentation" >
			<montant>104
			</montant>
			<pour coloc_id="Balthazar"/>
			<pour coloc_id="Gaspard"/>
			<pour coloc_id="Melchior"/>
			<pour coloc_id="Jesus"/>
		</depense>
	</actions>
	
	<colocataires>
		<coloc id="Melchior">Melchior</coloc>
		<coloc id ="Balthazar">Balthazar</coloc>
		<coloc id="Gaspard">Gaspard</coloc>
	</colocataires>

</comptes>

我的xsl文件:

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

  <xsl:template match="*/*">
    <xsl:apply-templates select=".//depense[@coloc_id='Balthazar']" mode="ok">
      <xsl:with-param name="personne">Balthazar</xsl:with-param>
    </xsl:apply-templates>
    <xsl:apply-templates select=".//depense[@coloc_id='Gaspard']" mode="ok">
      <xsl:with-param name="personne">Gaspard</xsl:with-param>
    </xsl:apply-templates>
    
    <xsl:apply-templates select=".//depense[@coloc_id='Melchior']" mode="ok">
      <xsl:with-param name="personne">Melchior</xsl:with-param>
    </xsl:apply-templates>
    <xsl:apply-templates select=".//depense[@coloc_id='Jesus']" mode="ok">
      <xsl:with-param name="personne">Jesus</xsl:with-param>
    </xsl:apply-templates>
  </xsl:template>
  
  <xsl:template match="*" mode="ok">
    <xsl:param name="personne"/>
    <xsl:value-of select="$personne"/>
    <xsl:text>:</xsl:text>
    <xsl:call-template name="DepenseMelchior">
      <xsl:with-param name="coloc"><xsl:value-of select="$personne"/></xsl:with-param>
      <xsl:with-param name="total">0</xsl:with-param>
      <xsl:with-param name="index_courant">1</xsl:with-param>
    </xsl:call-template>
    <xsl:text>.&#xa;</xsl:text>    
  </xsl:template>

  <xsl:template name="DepenseMelchior">
    <xsl:param name="coloc"/>
    <xsl:param name="total"/> 
    <xsl:param name="index_courant"/> 
    <xsl:choose> 
      <xsl:when test="$index_courant = count(*)+ 1"> 

        <xsl:value-of select="$total"/>
      </xsl:when> 
      <xsl:otherwise> 

        <xsl:choose> 
          <xsl:when test="self::node()[@coloc_id=$coloc]"> 
            <xsl:variable name="un_nombre"><xsl:value-of select="montant"/></xsl:variable>
            <xsl:call-template name="DepenseMelchior">
              <xsl:with-param name="total"><xsl:value-of select="$total  + $un_nombre"/></xsl:with-param> 
              <xsl:with-param name="index_courant"><xsl:value-of select="$index_courant + 1"/></xsl:with-param> 
            </xsl:call-template> 
          </xsl:when> 
          <xsl:otherwise> 
            <xsl:call-template name="DepenseMelchior"> 
              <xsl:with-param name="total"><xsl:value-of select="$total"/></xsl:with-param> 
              <xsl:with-param name="index_courant"><xsl:value-of select="$index_courant + 1"/></xsl:with-param>
            </xsl:call-template> 
          </xsl:otherwise>   
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


</xsl:stylesheet>

1 个答案:

答案 0 :(得分:1)

您可以使用key对节点进行分组。此示例对coloc元素进行模板设置,使用键将coloc_id匹配的金额相加。

请注意,这并不打印所有coloc的总和,因为colocataires列表中缺少其中一个( Jesus )。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>

    <!-- Map of depense by coloc_id -->
    <xsl:key name="depense-coloc" match="/comptes/actions/depense" use="@coloc_id"/>

    <!-- Template each coloc in the colocataires list -->
    <xsl:template match="/">
        <xsl:apply-templates select="/comptes/colocataires/coloc"/>
    </xsl:template>

    <!-- Template a coloc -->
    <xsl:template match="coloc">
        <!-- Name -->               <!-- Sum of depense/montant for matching coloc_id -->
        <xsl:value-of select="."/>: <xsl:value-of select="sum(key('depense-coloc', @id)/montant)"/>
<xsl:text>
</xsl:text>
    </xsl:template>

</xsl:stylesheet>

你可以使用递归,但它会更笨拙:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>

    <!-- Template each coloc in the colocataires list -->
    <xsl:template match="/">
        <xsl:apply-templates select="/comptes/colocataires/coloc"/>
    </xsl:template>

    <!-- Template a coloc -->
    <xsl:template match="coloc">
        <!-- Name -->               <!-- Template the first depense for matching coloc_id -->
        <xsl:value-of select="."/>: <xsl:apply-templates select="/comptes/actions/depense[@coloc_id=current()/@id][1]"/>
<xsl:text>
</xsl:text>
    </xsl:template>

    <!-- Sum the montant of a depense and all following depense elements -->
    <xsl:template match="depense">
        <xsl:variable name="next">
            <xsl:apply-templates select="following-sibling::depense[@coloc_id=current()/@coloc_id][1]"/>
        </xsl:variable>
        <xsl:value-of select="concat(0, $next) + montant"/>
    </xsl:template>

</xsl:stylesheet>

最后,一个直接的总和更清晰,更紧凑:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>

    <!-- Template each coloc in the colocataires list -->
    <xsl:template match="/">
        <xsl:apply-templates select="/comptes/colocataires/coloc"/>
    </xsl:template>

    <!-- Template a coloc -->
    <xsl:template match="coloc">
        <!-- Name -->               <!-- Sum of depense/montant for matching coloc_id -->
        <xsl:value-of select="."/>: <xsl:value-of select="sum(/comptes/actions/depense[@coloc_id=current()/@id]/montant)"/>
<xsl:text>
</xsl:text>
    </xsl:template>

</xsl:stylesheet>