2011-05-09 24 views
6

tengo xml que se ve algo como esto -Cómo dar salida a elementos duplicados usando XSLT?

<Root> 
    <Fields> 
    <Field name="abc" displayName="aaa" /> 
    <Field name="pqr" displayName="ppp" /> 
    <Field name="abc" displayName="aaa" /> 
    <Field name="xyz" displayName="zzz" /> 
    </Fields> 
</Root> 

Quiero que la salida contiene sólo aquellos elementos que tienen un name-displayName combinación repetir, si los hay -

<Root> 
     <Fields> 
     <Field name="abc" displayName="aaa" /> 
     <Field name="abc" displayName="aaa" /> 
     </Fields> 
</Root> 

cómo puedo hacer esto usando XSLT?

+0

Buena pregunta, +1. Vea mi respuesta para una solución XSLT 1.0 corta, fácil y eficiente. –

+0

También se agregó una solución XSLT 2.0. –

+0

¿Te resultó útil esta respuesta? –

Respuesta

7

Esta transformación:

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

<xsl:key name="kFieldByName" match="Field" 
    use="concat(@name, '+', @displayName)"/> 

<xsl:template match= 
    "Field[generate-id() 
     = 
     generate-id(key('kFieldByName', 
        concat(@name, '+', @displayName) 
        )[2]) 
     ] 
    "> 
    <xsl:copy-of select= 
    "key('kFieldByName',concat(@name, '+', @displayName))"/> 
</xsl:template> 
</xsl:stylesheet> 

cuando se aplica sobre el documento XML proporcionado:

<Root> 
    <Fields> 
     <Field name="abc" displayName="aaa" /> 
     <Field name="pqr" displayName="ppp" /> 
     <Field name="abc" displayName="aaa" /> 
     <Field name="xyz" displayName="zzz" /> 
    </Fields> 
</Root> 

produce el resultado deseado:

<Field name="abc" displayName="aaa"/> 
<Field name="abc" displayName="aaa"/> 

Explicación:

  1. Muenchian grouping usando la clave compuesta (en los atributos name y displayName).

  2. La única plantilla en el código coincide con cualquier elemento Field que sea el segundo en su grupo correspondiente. Luego, dentro del cuerpo de la plantilla, se genera todo el grupo.

  3. agrupación Muenchian es forma eficiente de agrupar en XSLT 1.0. Las claves se usan para la eficiencia.

  4. Ver también mi respuesta a this question.

II. XSLT 2.0 solución:

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:for-each-group select="/*/*/Field" 
      group-by="concat(@name, '+', @displayName)"> 
     <xsl:sequence select="current-group()[current-group()[2]]"/> 
    </xsl:for-each-group> 
</xsl:template> 
</xsl:stylesheet> 

Cuando se aplica esta transformación en el documento XML proporcionado (se muestra más arriba), de nuevo el resultado deseado, correcta se produce:

<Field name="abc" displayName="aaa"/> 
<Field name="abc" displayName="aaa"/> 

Explicación:

  1. Uso de <xsl:for-each-group>

  2. Uso de la función current-group().

1

para encontrar duplicados, es necesario repetir los elementos Field y para cada uno, busca el conjunto de Field elementos en todo el documento que se emparejan name y displayName valores de atributos. Si el conjunto tiene más de 1 elemento, agrega ese elemento a la salida.

Aquí es un ejemplo de una plantilla que logra esto:

<xsl:template match="Field"> 
    <xsl:variable name="fieldName" select="@name" /> 
    <xsl:variable name="fieldDisplayName" select="@displayName" /> 
    <xsl:if test="count(//Field[@name=$fieldName and @displayName=$fieldDisplayName]) > 1"> 
     <xsl:copy-of select="."/> 
    </xsl:if> 
</xsl:template> 

La ejecución de esta plantilla (envuelto en un archivo XSLT apropiado) en sus datos de muestra da el siguiente resultado:

<?xml version="1.0" encoding="utf-8"?> 
<Root> 
    <Fields> 
    <Field name="abc" displayName="aaa" /> 
    <Field name="abc" displayName="aaa" /> 
    </Fields> 
</Root> 
+0

@Jeff Yates: esta es una posible solución, sin embargo, su eficacia es O (N^2) y es demasiado lenta para ser utilizada en documentos XML con una gran cantidad de elementos de 'Campo'. Vea mi respuesta para una solución eficiente. –

+0

@Dimitre: Parece una tontería hacer más esfuerzo de lo necesario. No hay ninguna razón para creer que el XML real sería enorme y no hay información de perfil. Me apresuro a escribir rápidamente para ejecutarlo cualquier día hasta que se establezca el perfil. –

+0

@Jeff Yates: se pueden y se deben usar las soluciones conocidas más eficientes. Debido a que la gente piensa lo contrario, nos encontramos con los problemas de todos los días sobre una transformación que dura 40 minutos y cuando se refactura con la agrupación Muenchian y luego toma solo 2 segundos. No deberíamos propagar algoritmos malos e ingenuos. –

Cuestiones relacionadas