节点上的XSLT 1.0逻辑

时间:2013-05-28 16:41:02

标签: xslt

相等的节点应该在单个计数器元素下。 输入:

<Move-Afile>
  <Afile>
    <Item>
    <PACK050>
      <PackNumber>1234</PackNumber>
      </PACK050>
    </Item>
    <Item>
    <PACK050>
      <PackNumber>567</PackNumber>
      </PACK050>
    </Item>
    <Item>
    <PACK050>
      <PackNumber>567</PackNumber>
      </PACK050>
    </Item>
    <Item>
    <PACK050>
      <PackNumber>126</PackNumber>
      </PACK050>
    </Item>
    <Item>
    <PACK050>
      <PackNumber>567</PackNumber>
      </PACK050>
    </Item>
  </Afile>
</Move-Afile>

对于每个包号,我们需要递增计数器变量,但是这里存在一个条件,如果previous等于current,我们必须忽略计数器(不需要递增),如下面的output.all等于节点来自一个计数器,如下面的输出。

XSLT模板应该包含<for-each>,如下面的结构。

<xsl:template match="/">
  <A>
    <target>
      <xsl:for-each select="/Move-Afile/Afile/Item/PACK050/PackNumber">

        <xsl:variable name="count">
          <!-- get the count here-->
        </xsl:variable>

        <counter>$count</counter>
        <PNumber><xsl:value-of select="."/></PNumber>

      </xsl:for-each>
    </target>
  </A>
</xsl:template>

输出:

<A>
  <target>
    <Item>
    <PACK050>
      <counter>1</counter><!-- if previous <PackNumber> is not equal to current <PackNumber> increment the count-->
      <PNumber>1234</PNumber>
      </PACK050>
    </Item>
    <Item
    <PACK050>
      <counter>2</counter><!-- if previous <PackNumber> is not equal to current <PackNumber> increment the count-->
      <PNumber>567</PNumber>
      </PACK050>
    </Item>
    <Item><!-- if previous <PackNumber> is  equal to current <PackNumber> ignore the counter -->
      <PACK050>
      <PNumber>567</PNumber>
      </PACK050>
    </Item>
    <Item><!-- if previous <PackNumber> is  equal to current <PackNumber> ignore the counter -->
      <PACK050>
      <PNumber>567</PNumber>
      </PACK050>
    </Item>
    <Item>
    <PACK050>
      <counter>3</counter><!-- if previous <PackNumber> is not equal to current <PackNumber> increment the count-->
      <PNumber>126</PNumber>
      </PACK050>
    </Item>

  </target>
</A>

2 个答案:

答案 0 :(得分:3)

不要将其视为递增计数器,将其视为对相似节点进行分组。您在此处尝试执行的操作是按ItemPackNumber个元素进行分组,然后为每个组写出第一个匹配的Item,其值为counter,其余没有。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:key name="itemByPnum" match="Item" use="PACK050/PackNumber" />

  <xsl:template match="/">
    <A>
      <target>
        <xsl:apply-templates select="Move-Afile/Afile/Item[generate-id() =
             generate-id(key('itemByPnum', PACK050/PackNumber)[1])]" />
      </target>
    </A>
  </xsl:template>

  <xsl:template match="Item">
    <xsl:apply-templates select="." mode="copy">
      <xsl:with-param name="counter">
        <counter><xsl:value-of select="position()" /></counter>
      </xsl:with-param>
    </xsl:apply-templates>
    <!-- copy without the <counter> all matching Items except the first one -->
    <xsl:apply-templates mode="copy"
          select="key('itemByPnum', PACK050/PackNumber)
          [generate-id() != generate-id(current())]" />
  </xsl:template>

  <xsl:template match="Item" mode="copy">
    <xsl:param name="counter" />
    <Item>
      <PACK050>
        <xsl:copy-of select="$counter" />
        <PNumber><xsl:value-of select="PACK050/PackNumber" /></PNumber>
      </PACK050>
    </Item>
  </xsl:template>
</xsl:stylesheet>

这是一种称为Muenchian分组的技术示例。 apply-templates模板中的初始/会为每个Item提取第一个 PackNumberItem模板会生成正确的输出对于那个小组。

答案 1 :(得分:2)

这个问题实际上可以通过使用着名的Muhnchian分组方法来解决XSLT 1.0。

当这个XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="kItemByPackNo" match="Item" use="*/PackNumber"/>

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

  <xsl:template match="/*">
    <A>
      <target>
        <xsl:apply-templates
          select="*/Item[generate-id() = 
                         generate-id(key('kItemByPackNo', */PackNumber)[1])]"/>
      </target>
    </A>
  </xsl:template>

  <xsl:template match="Item">
    <Item>
      <counter>
        <xsl:value-of select="position()"/>
      </counter>
      <xsl:apply-templates/>
    </Item>
    <xsl:copy-of
      select="key('kItemByPackNo', */PackNumber)[
                not(generate-id() = generate-id(current()))
              ]"/>
  </xsl:template>

  <xsl:template match="PackNumber">
    <PNumber>
      <xsl:apply-templates/>
    </PNumber>
  </xsl:template>

</xsl:stylesheet>

...适用于提供的XML:

<Move-Afile>
  <Afile>
    <Item>
      <PACK050>
        <PackNumber>1234</PackNumber>
      </PACK050>
    </Item>
    <Item>
      <PACK050>
        <PackNumber>567</PackNumber>
      </PACK050>
    </Item>
    <Item>
      <PACK050>
        <PackNumber>567</PackNumber>
      </PACK050>
    </Item>
    <Item>
      <PACK050>
        <PackNumber>126</PackNumber>
      </PACK050>
    </Item>
    <Item>
      <PACK050>
        <PackNumber>567</PackNumber>
      </PACK050>
    </Item>
  </Afile>
</Move-Afile>

...产生了所需的结果:

<A>
  <target>
    <Item>
      <counter>1</counter>
      <PACK050>
        <PNumber>1234</PNumber>
      </PACK050>
    </Item>
    <Item>
      <counter>2</counter>
      <PACK050>
        <PNumber>567</PNumber>
      </PACK050>
    </Item>
    <Item>
      <PACK050>
        <PackNumber>567</PackNumber>
      </PACK050>
    </Item>
    <Item>
      <PACK050>
        <PackNumber>567</PackNumber>
      </PACK050>
    </Item>
    <Item>
      <counter>3</counter>
      <PACK050>
        <PNumber>126</PNumber>
      </PACK050>
    </Item>
  </target>
</A>