代码之家  ›  专栏  ›  技术社区  ›  knipknap

分组和删除重复项

  •  0
  • knipknap  · 技术社区  · 15 年前

    给定以下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 回复  |  直到 12 年前
        1
  •  2
  •   Community paulsm4    7 年前

    XSLT 1:

    <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. 追加一个 ':' (=> 'Serial2/0.0:' ; 'Serial3/0:1:' )
    2. 在第一次之前把所有东西都拿走 “:” (=); “串行2/0” ; 'Serial3/0' )
    3. 追加一个 '.' (=); 'Serial2/0.0.' ; 'Serial3/0.' )
    4. 在第一次之前把所有东西都拿走 “.” (=); 'Serial2/0' ; “串行3/0” )

    编辑:简化的xpath表达式。我的第一次尝试成功了,但更复杂:

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

    在加号方面,上述表达式正确处理名称第一部分的冒号和圆点,例如 'Some.Serial3/0:1' .矮一点的不行。如果名称中需要点,请使用较长的表达式。它的解释在 revision history of this post .

        2
  •  1
  •   Rubens Farias    15 年前

    你应该看看 Muenchian method 将XML项分组。