使用XSLT在xml中计算相同的值

时间:2012-12-24 06:30:51

标签: xml xslt xpath xslt-2.0

我想在输出中添加<LineNum>[number]</LineNum>,如果我们在<cell num="4">

中有不同的值,则LineNum必须再次从'1'开始

来源xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<table>
   <sheet name="Notification" num="1">
      <row num="1">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027830(010000)</cell>
         <cell num="4">800015001</cell>
      </row>
      <row num="2">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027830(010000)</cell>
         <cell num="4">800015001</cell>
      </row>
      <row num="3">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027831(010000)</cell>
         <cell num="4">800015002</cell>
      </row>
      <row num="4">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027831(010000)</cell>
         <cell num="4">800015002</cell>
      </row>
      <row num="5">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027831(010000)</cell>
         <cell num="4">800015002</cell>
      </row>
   </sheet>
</table>

在这种情况下也是如此:

<cell num="4">800015001</cell>
<LineNum>1</LineNum>
<cell num="4">800015001</cell>
<LineNum>2</LineNum>

<!-- cell num="4" different from previous, start LineNum from 1 -->
<cell num="4">800015002</cell>
<LineNum>1</LineNum>
<cell num="4">800015002</cell>
<LineNum>2</LineNum>
<cell num="4">800015002</cell>
<LineNum>3</LineNum>

我可以添加全局变量,为其分配单元格num =“4”,然后检查当前值是否与全局变量相同,否则 - 再次从1开始LineNum并重新分配全局变量。可悲的是,XSLT不提供重新分配。

我该怎么办?

UPD: 试图以某种方式修改其他问题XSL: Counting Previous Unique Siblings的例子,但没有运气..

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

  <xsl:output method="text"/>

  <!-- don't copy whitespace -->
  <xsl:template match="text()"/>

  <xsl:template match="row/cell[@num=4]">
    <xsl:variable name="roles-so-far" select=". | preceding::row/cell[@num=4]"/>
    <xsl:value-of select="count($roles-so-far)"/>
    <xsl:value-of select="' '"/>
    <xsl:value-of select="."/>

    <!-- Only select the first instance of each ROLE name -->
    <xsl:variable name="roles-so-far-unique"
                  select="$roles-so-far[not(. = preceding-sibling::row/cell[@num=4])]"/>

    <xsl:apply-templates select="/"/>
    <xsl:text> </xsl:text>
    <xsl:value-of select="count($roles-so-far-unique)"/>
    <xsl:text>&#xA;</xsl:text> <!-- linefeed -->


  </xsl:template>

</xsl:stylesheet>

1 个答案:

答案 0 :(得分:1)

将问题标记为xslt-2.0,您可以轻松使用for-each-group group-adjacent

<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:strip-space elements="*"/>

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

<xsl:template match="sheet">
  <xsl:copy>
    <xsl:for-each-group select="row" group-adjacent="cell[@num = 4]">
      <xsl:apply-templates select="current-group()"/>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

<xsl:template match="row">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()"/>
    <LineNum><xsl:value-of select="position()"/></LineNum>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

当我将以上代码与Saxon 9.4应用于您的输入样本时,我得到以下结果:

<table>
   <sheet>
      <row num="1">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027830(010000)</cell>
         <cell num="4">800015001</cell>
         <LineNum>1</LineNum>
      </row>
      <row num="2">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027830(010000)</cell>
         <cell num="4">800015001</cell>
         <LineNum>2</LineNum>
      </row>
      <row num="3">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027831(010000)</cell>
         <cell num="4">800015002</cell>
         <LineNum>1</LineNum>
      </row>
      <row num="4">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027831(010000)</cell>
         <cell num="4">800015002</cell>
         <LineNum>2</LineNum>
      </row>
      <row num="5">
         <cell num="1">IBD</cell>
         <cell num="2">YES</cell>
         <cell num="3">6600027831(010000)</cell>
         <cell num="4">800015002</cell>
         <LineNum>3</LineNum>
      </row>
   </sheet>
</table>