分组和删除重复的项目

时间:2010-01-22 08:34:33

标签: xslt grouping duplicates distinct

给出以下XML:

<interface name="Serial1/0"/>
<interface name="Serial2/0.0"/>
<interface name="Serial2/0.1"/>
<interface name="Serial3/0:0"/>
<interface name="Serial3/0:1"/>

我正在尝试生成以下输出:

<interface name="Serial1/0">
  <unit name="Serial1/0"/>
</interface>
<interface name="Serial2/0">
  <unit name="Serial2/0.0"/>
  <unit name="Serial2/0.1"/>
</interface>
<interface name="Serial3/0">
  <unit name="Serial3/0:0"/>
  <unit name="Serial3/0:1"/>
</interface>

我创建了以下用于拆分字符串的函数:

<xsl:template name="getPhysicalInterfaceName">
  <xsl:param name="interfaceName"/>
  <xsl:choose>
    <xsl:when test="contains($interfaceName, ':')">
      <xsl:value-of select="substring-before($interfaceName, ':')"/>
    </xsl:when>
    <xsl:when test="contains($interfaceName, '.')">
      <xsl:value-of select="substring-before($interfaceName, '.')"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$interfaceName"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

我找到了使用xsl:key元素的引用,但是我没有看到在上下文中使用它的明显方法。任何的想法? (我正在使用xsltproc(XSLT1.0)进行转换。)

2 个答案:

答案 0 :(得分:2)

XSLT 1.0:

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:key 
    name  = "kInterfaceByName" 
    match = "interface"
    use   = "
      substring-before(concat(
        substring-before(concat(@name, ':'), ':'),
      '.'), '.')
    "
  />

  <xsl:template match="i">
    <xsl:copy>
      <xsl:apply-templates mode="group" select="interface" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="interface" mode="group">
    <xsl:variable name="name" select="
      substring-before(concat(
        substring-before(concat(@name, ':'), ':'),
      '.'), '.')
    " />
    <xsl:variable name="interfaces" select="key('kInterfaceByName', $name)" />

    <!-- Muenchian step -->
    <xsl:if test="generate-id()=generate-id($interfaces[1])">
      <interface name="{$name}">
        <xsl:apply-templates mode="unit" select="$interfaces" />
      </interface>
    </xsl:if>
  </xsl:template>

  <xsl:template match="interface" mode="unit">
    <unit name="{@name}" />
  </xsl:template>


</xsl:stylesheet>

应用于

<i>
  <interface name="Serial1/0"/>
  <interface name="Serial2/0.0"/>
  <interface name="Serial2/0.1"/>
  <interface name="Serial3/0:0"/>
  <interface name="Serial3/0:1"/>
</i>

结果

<i>
  <interface name="Serial1/0">
    <unit name="Serial1/0" />
  </interface>
  <interface name="Serial2/0">
    <unit name="Serial2/0.0" />
    <unit name="Serial2/0.1" />
  </interface>
  <interface name="Serial3/0">
    <unit name="Serial3/0:0" />
    <unit name="Serial3/0:1" />
  </interface>
</i>

XPath表达式取代了您的getPhysicalInterfaceName模板。

'Serial2/0.0''Serial3/0:1'的示例:

  1. 追加':'(=&gt; 'Serial2/0.0:'; 'Serial3/0:1:'
  2. 在第一个':'(=&gt; 'Serial2/0.0'; 'Serial3/0'
  3. 之前采取一切措施
  4. 追加'.'(=&gt; 'Serial2/0.0.'; 'Serial3/0.'
  5. 在第一个'.'(=&gt; 'Serial2/0'; 'Serial3/0'
  6. 之前采取一切措施

    编辑:简化的XPath表达式。我的第一次尝试工作但更复杂:

    concat(
      substring-before(@name, '/'), 
      '/',
      substring-before(
        concat(
          translate(substring-after(@name, '/'), '.', ':'), ':'
        ),
        ':'
      )
    )
    

    在正面,上面的表达式正确处理名称第一部分中的冒号和点,例如'Some.Serial3/0:1'。较短的没有。如果您希望名称中有点,请使用更长的表达式。对它的解释是在revision history of this post

答案 1 :(得分:1)

您应该查看Muenchian method以对XML项目进行分组。