XSL计数器循环转换

时间:2012-07-03 07:37:53

标签: xslt

我想写一个xsl转换,但我被困在“计数器”部分。 这基本上就是我想做的事情:

输入文件:

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <Pallets>
    <Pallet>
       <Line>
         <Product>test</Product>
       </Line>
       <Line>
         <Product>test2</Product>
       </Line>
    </Pallet>
    <Pallet>
      <Line>
        <Product>test_1</Product>
      </Line>
      <Line>
        <Product>test_2</Product>
      </Line>
     </Pallet>
   </Pallets>
</root>

这就是我想要的输出:

<?xml version="1.0" encoding="utf-8"?>
<Result>
  <Pallet>
    <ID>2</ID> ==> This is a counter that increments starting from 2
    <ID2>1</ID2> ==> Always "1"
    <Line>
      <ID>3</ID> ==> The counter from above that increments
      <ParentID>2</ParentID> ==> PalletID (ID from above the loop)
      <Name>test</Name>
    </Line>
    <Line>
      <ID>4</ID> ==> The counter from above that increments
      <ParentID>2</ParentID> ==> PalletID
      <Name>test2</Name>
    </Line>
  </Pallet>
  <Pallet>
    <ID>5</ID>  ==> The counter from above that increments
    <ID2>1</ID2> ==> Always "1"
    <Line>
      <ID>6</ID> ==> The counter from above that increments
      <ParentID>5</ParentID> ==> PalletID
      <Name>test_1</Name>
    </Line>
    <Line>
      <ID>7</ID> ==> The counter from above that increments
      <ParentID>5</ParentID> ==> PalletID
      <Name>test_2</Name>
    </Line>
  </Pallet>
</Result>

任何人都可以帮我吗? 这是我到目前为止,但正如您将看到的,palletId的计数器不正确。第二个托盘ID应该是ID = 5而不是3:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <Result>
      <xsl:for-each select="root/Pallets/Pallet">
        <xsl:variable name="counter" select="1" />
        <Pallet>
          <xsl:variable name="Parentcounter" select="position() + $counter" />
          <ID>
            <xsl:value-of select="$Parentcounter"/>
          </ID>
          <ID2>1</ID2>
          <xsl:for-each select="Line">
            <Line>
              <ID>
                <xsl:value-of select="$Parentcounter + position()"/>
              </ID>
              <ParentID>
                <xsl:value-of select="$Parentcounter"/>
              </ParentID>
              <Name>
                <xsl:value-of select="Product"/>
              </Name>
            </Line>
          </xsl:for-each>
        </Pallet>
      </xsl:for-each>
    </Result>
  </xsl:template>
</xsl:stylesheet>

提前致谢。

2 个答案:

答案 0 :(得分:1)

您只需计算前面托盘的数量,即可获得托盘元素的 ID 元素

<xsl:variable name="id" select="count(preceding::Pallet|preceding::Line) + 2" />
<ID><xsl:value-of select="$id" /></ID>

如果您在匹配元素的模板中将其作为参数传递,则元素的 ID 将如下所示(其中) $ parentID包含父级的id

<ID><xsl:value-of select="$ParentID + count(preceding-sibling::Line) + 1" /></ID>

因此,以下XSLT应该产生所需的输出

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

   <xsl:template match="Pallets">
      <Result>
         <xsl:apply-templates select="Pallet" />
      </Result>
   </xsl:template>

   <xsl:template match="Pallet">
      <xsl:variable name="id" select="count(preceding::Pallet|preceding::Line) + 2" />
      <Pallet>
         <ID><xsl:value-of select="$id" /></ID>
         <ID2>1</ID2>
         <xsl:apply-templates select="Line">
            <xsl:with-param name="ParentID" select="$id" />
         </xsl:apply-templates>
      </Pallet>
   </xsl:template>

   <xsl:template match="Line">
      <xsl:param name="ParentID" />
      <Line>
         <ID><xsl:value-of select="$ParentID + count(preceding-sibling::Line) + 1" /></ID>
         <ParentID><xsl:value-of select="$ParentID" /></ParentID>
         <Name><xsl:value-of select="Product" /></Name>
      </Line>
   </xsl:template>
</xsl:stylesheet>

然而,对于更大数量的托盘和物品来说,这不一定有效,因为它必须重复计算更多的前面元素(基本上反复计算相同的东西)。另一种方法是使用递归模板,每次将Pallet的ID的运行总和作为参数传递。试试这个XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:template match="Pallets">
      <Result>
         <xsl:apply-templates select="Pallet[1]"/>
      </Result>
   </xsl:template>

   <xsl:template match="Pallet">
      <xsl:param name="id" select="2"/>
      <Pallet>
         <ID>
            <xsl:value-of select="$id"/>
         </ID>
         <ID2>1</ID2>
         <xsl:apply-templates select="Line[1]">
            <xsl:with-param name="parentID" select="$id"/>
         </xsl:apply-templates>
      </Pallet>
      <xsl:apply-templates select="following-sibling::Pallet[1]">
         <xsl:with-param name="id" select="$id + count(Line) + 1"/>
      </xsl:apply-templates>
   </xsl:template>

   <xsl:template match="Line">
      <xsl:param name="parentID"/>
      <xsl:param name="id" select="$parentID + 1"/>
      <Line>
         <ID>
            <xsl:value-of select="$id"/>
         </ID>
         <ParentID>
            <xsl:value-of select="$parentID"/>
         </ParentID>
         <Name>
            <xsl:value-of select="Product" />
         </Name>
      </Line>

      <xsl:apply-templates select="following-sibling::Line[1]">
         <xsl:with-param name="parentID" select="$parentID"/>
         <xsl:with-param name="id" select="$id + 1"/>
      </xsl:apply-templates>
   </xsl:template>
</xsl:stylesheet>

这也会产生相同的输出

<Result>
   <Pallet>
      <ID>2</ID>
      <ID2>1</ID2>
      <Line>
         <ID>3</ID>
         <ParentID>2</ParentID>
         <Name>test</Name>
      </Line>
      <Line>
         <ID>4</ID>
         <ParentID>2</ParentID>
         <Name>test2</Name>
      </Line>
   </Pallet>
   <Pallet>
      <ID>5</ID>
      <ID2>1</ID2>
      <Line>
         <ID>6</ID>
         <ParentID>5</ParentID>
         <Name>test_1</Name>
      </Line>
      <Line>
         <ID>7</ID>
         <ParentID>5</ParentID>
         <Name>test_2</Name>
      </Line>
   </Pallet>
</Result>

答案 1 :(得分:0)

使用

<xsl:number level="any" count="Pallet|Line"/>

因为你从2开始,你必须把它放在一个变量中并加一个。