2

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

<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>

对于每个包号,我们需要增加计数器变量,但是这里存在一个条件,例如如果先前等于当前,我们必须忽略计数器(无需增加),如下面的输出。所有相等的节点都在一个之下计数器如下输出。

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>
4

2 回答 2

3

不要将其视为递增计数器,将其视为对相似节点的分组。您在这里尝试做的是按元素对Item元素进行分组PackNumber,然后为每个组写出第一个匹配Itemcounter值,其余的不匹配。

<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模板中的字母/提取每个的第一个,然后模板为该组生成正确的输出。 ItemPackNumberItem

于 2013-05-28T16:58:44.563 回答
2

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

当这个 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>
于 2013-05-28T16:58:06.297 回答