2009-03-14 9 views
6

Ho un XML come questoXSLT: Unire scenario duplicato

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

voglio che il mio output XML per essere come questo

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

Qui, il 'FILEDATA' di competenza corrispondenti "contractNo" bisogni da combinare in uscita. Questa trasformazione può essere raggiunta con XSLT?

Grazie in anticipo.

Srini

+0

versione di XSLT e piattaforma può essere utile – AnthonyWJones

risposta

7

il seguente XSLT 1.0 trasformazione produce il risultato corretto:

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

noti l'uso di <xsl:key> in combinazione con generate-id() per identificare il primo nodo di un insieme corrispondente nodo, raggruppando efficacemente nodi pari insieme.

È possibile forzare un risultato ordinato utilizzando <xsl:sort> all'interno dello <xsl:apply-templates>. Non l'ho incluso per motivi di chiarezza.

La mia uscita di test è:

<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

E 'relativamente facile estendere la trasformazione di escludere duplicati nodi pure. Dal momento che non era parte del requisito originale, l'ho lasciato come esercizio per il lettore. ;-) Suggerimento: è richiesto un ulteriore e un altro . – Tomalak

+0

ciao, roba geniale ... c'è qualche link per studiare questi concetti in modo molto dettagliato? Puoi suggerire uno che copra queste trasformazioni dalle basi? –

+0

Ci sono un sacco di siti Web e tutorial XSLT/XPath su Internet. Google solo le parti che non capisci. A seconda del livello attuale di conoscenza dell'XSLT, la soluzione potrebbe richiedere del tempo per diventare trasparente. ;-) – Tomalak