2010-01-22 5 views
0

Étant donné le code XML suivant:Regroupement et supprimer les éléments dupliqués

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

Je suis en train de produire la sortie suivante:

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

J'ai créé la fonction suivante pour diviser la chaîne:

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

J'ai trouvé des références à l'utilisation de l'élément xsl: key, mais je n'ai pas trouvé de moyen évident de l'utiliser dans le cadre. Une idée? (J'utilise xsltproc (XSLT1.0) pour effectuer la transformation.)

+0

Ce n'est pas valide XML – Oded

+0

Huh? Quelle partie n'est pas valide XML? – knipknap

+0

Strictement parlant: l'élément de document de niveau supérieur est manquant. ;-) – Tomalak

Répondre

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> 

lorsqu'il est appliqué à

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

résultats dans

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

L'expression XPath remplace votre modèle getPhysicalInterfaceName.

Il fait, les exemples de 'Serial2/0.0' et 'Serial3/0:1':

  1. ajouter un ':' (=>'Serial2/0.0:'; 'Serial3/0:1:')
  2. prendre tout avant la première ':' (=>'Serial2/0.0'; 'Serial3/0')
  3. ajouter un '.' (=>'Serial2/0.0.'; 'Serial3/0.')
  4. prendre tout avant le f le premier '.' (=>'Serial2/0'; 'Serial3/0')

EDIT: expression XPath simplifié. Mon premier essai a fonctionné mais était plus complexe:

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

Du côté positif, l'expression ci-dessus est capable de traiter et des points dans les deux points de la première partie du nom, par exemple 'Some.Serial3/0:1'. Le plus court ne le fait pas. Si vous attendez des points dans le nom, utilisez l'expression plus longue. Une explication de cela est dans le revision history of this post.

+0

Merci beaucoup pour la réponse à long, cela a été très utile! – knipknap

+0

De rien. ;) – Tomalak

1

Vous devriez jeter un oeil à Muenchian method pour regrouper des éléments XML.

+0

Merci, cela semble utile. Le principal problème que j'ai avec la méthode est comment utiliser ma méthode getPhysicalInterfaceName() pour séparer les éléments qui sont ajoutés dans la clé xsl:. Cela ne fonctionne pas: 'use = "getPhysicalInterfaceName (@name)"'. – knipknap

+0

essayer de créer une variable avec ces noms et, eux, d'appliquer ce code –

Questions connexes