2009-03-14 8 views
6

tengo un XML como estoXSLT: Combinar escenario duplicado

<ContractInfo ContractNo="12345"> 
       <Details LastName="Goodchild">       
         <Filedata FileName="File1"/> 
       </Details> 
</ContractInfo> 

<ContractInfo ContractNo="12345"> 
       <Details LastName="Goodchild">       
         <Filedata FileName="File2"/> 
       </Details> 
</ContractInfo> 

<ContractInfo ContractNo="123456"> 
       <Details LastName="Goodchild">       
         <Filedata FileName="File2"/> 
       </Details> 
</ContractInfo> 

Quiero que mi salida XML sea así

<ContractInfo ContractNo="12345"> 
       <Details LastName="Goodchild">       
         <Filedata FileName="File1"/> 
         <Filedata FileName="File2"/> 
       </Details> 
</ContractInfo> 

<ContractInfo ContractNo="123456"> 
       <Details LastName="Goodchild">       
         <Filedata FileName="File2"/> 
       </Details> 
</ContractInfo> 

Aquí, el 'FileData' pertenecientes a adecuarse a las necesidades "contractNo" para combinar en la salida. ¿Se puede lograr esta transformación con XSLT?

Gracias de antemano.

Srini

+0

versión de XSLT y la plataforma puede ser útil – AnthonyWJones

Respuesta

7

La siguiente transformación XSLT 1.0 produce el resultado correcto:

<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="xml" indent="yes" /> 

    <xsl:key name="contract" match="ContractInfo" use="@ContractNo" /> 
    <xsl:key name="filedata" match="Filedata" use="../../@ContractNo" /> 

    <xsl:template match="ContractInfo"> 
    <xsl:if test="generate-id() = 
        generate-id(key('contract', @ContractNo)[1])"> 
     <xsl:copy> 
     <xsl:apply-templates select="key('contract', @ContractNo)/Details | @*" /> 
     </xsl:copy> 
    </xsl:if> 
    </xsl:template> 

    <xsl:template match="Details"> 
    <xsl:if test="generate-id(..) = 
        generate-id(key('contract', ../@ContractNo)[1])"> 
     <xsl:copy> 
     <xsl:apply-templates select="key('filedata', ../@ContractNo) | @*" /> 
     </xsl:copy> 
    </xsl:if> 
    </xsl:template> 

    <!-- copy everything else (root node, Filedata nodes and @attributes) --> 
    <xsl:template match="* | @*"> 
    <xsl:copy> 
     <xsl:apply-templates select="* | @*" /> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

Nota el uso de <xsl:key> en conjunción con generate-id() para identificar el primer nodo de un conjunto de nodos de coincidencia, la agrupación de manera efectiva la igualdad de nodos juntos.

Puede forzar un resultado ordenado utilizando <xsl:sort> dentro del <xsl:apply-templates>. No incluí eso por el bien de la claridad.

Mi salida de prueba es:

<root> 
    <ContractInfo ContractNo="12345"> 
    <Details LastName="Goodchild"> 
     <Filedata FileName="File1"></Filedata> 
     <Filedata FileName="File2"></Filedata> 
    </Details> 
    </ContractInfo> 
    <ContractInfo ContractNo="123456"> 
    <Details LastName="Goodchild"> 
     <Filedata FileName="File2"></Filedata> 
    </Details> 
    </ContractInfo> 
</root> 
+0

Es relativamente fácil de extender la transformación de excluir duplicados nodos también. Como eso no formaba parte del requisito original, lo dejé como ejercicio para el lector. ;-) Sugerencia: Se requiere un adicional y otro . – Tomalak

+0

hola, cosas brillantes ... ¿hay algún enlace para estudiar estos conceptos con mucho detalle? ¿Puedes sugerir uno que cubra estas transformaciones desde lo básico? –

+0

Hay muchos sitios web relacionados con XSLT/XPath y tutoriales en Internet. Solo busca en google las partes que no entiendes. Dependiendo de su nivel actual de conocimiento XSLT, la solución puede tardar un tiempo en volverse transparente. ;-) – Tomalak