2012-09-18 6 views
5

ho creato un XSLT e mi chiedevo come sia possibile copiare tutti i nodi tra una serie di tag, e aggiungere un altro tag nella parte inferiore. Ho creato l'XSLT che ha tutta la logica per determinare quale tag aggiungere e come dovrebbe essere chiamato. Tuttavia il problema che sto ottenendo è che non posso copiare anche tutti gli altri tag. Qui di seguito sono i file in questione:XSLT - Copia tutti gli altri nodi, aggiungere 1 nuovo nodo

XSLT

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="/csvImportSchema"> 
     <csvImportSchema> 
      <xsl:for-each select="payload"> 
       <payload> 
        <xsl:copy-of select="@*"/> 
        <xsl:variable name="ean"> 
         <xsl:value-of select="ean"/> 
        </xsl:variable> 
        <xsl:for-each select="../product"> 
         <xsl:if test="ean = $ean"> 
          <productId><xsl:value-of select="article"/></productId> 
         </xsl:if> 
        </xsl:for-each> 
       </payload> 
      </xsl:for-each> 
     </csvImportSchema> 
    </xsl:template> 

</xsl:stylesheet> 

INPUT

<?xml version="1.0" encoding="UTF-8"?> 
<csvImportSchema> 
    <payload> 
     <test>1</test> 
     <test2>2</test2> 
     <test3>3</test3> 
     <ean>1111111111</ean> 
     <productId/> 
    </payload> 
    <product> 
     <article>722619</article> 
     <ean>1111111111</ean> 
    </product> 
</csvImportSchema> 

USCITA CORRENTE

<?xml version="1.0" encoding="utf-8"?> 
<csvImportSchema> 
    <payload> 
     <productId>722619</productId> 
    </payload> 
</csvImportSchema> 

output desiderato

<?xml version="1.0" encoding="UTF-8"?> 
<csvImportSchema> 
    <payload> 
     <test>1</test> 
     <test2>2</test2> 
     <test3>3</test3> 
     <ean>1111111111</ean> 
     <productId>722619</productId> 
    </payload> 
</csvImportSchema> 

risposta

7

Questa breve e semplice trasformazione:

<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:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="productId"> 
    <productId> 
    <xsl:value-of select="../../product/article"/> 
    </productId> 
</xsl:template> 
<xsl:template match="product"/> 
</xsl:stylesheet> 

quando applicato sul documento XML fornito:

<csvImportSchema> 
    <payload> 
     <test>1</test> 
     <test2>2</test2> 
     <test3>3</test3> 
     <ean>1111111111</ean> 
     <productId/> 
    </payload> 
    <product> 
     <article>722619</article> 
     <ean>1111111111</ean> 
    </product> 
</csvImportSchema> 

produce il desiderato, risultato corretto:

<csvImportSchema> 
    <payload> 
     <test>1</test> 
     <test2>2</test2> 
     <test3>3</test3> 
     <ean>1111111111</ean> 
     <productId>722619</productId> 
    </payload> 
</csvImportSchema> 

Spiegazione:

  1. I identity rule copie "così com'è" ogni nodo per il quale esso è stato selezionato per l'esecuzione.

  2. Un modello sovrascrivente che corrisponde a product "elimina" questo elemento dall'output (dal suo corpo vuoto).

  3. Un altro modello di sovrapposizione corrisponde a productId e genera questo elemento con un figlio di nodo di testo prelevato da product/article.

1

Dovrebbe essere semplice come cambiare la vostra payload xsl:copy-of select="@*"/ a

<xsl:copy-of select="*[local-name() != 'productId'] | @*"/> 

cioè copiare tutto, tranne productId, perché si costruisce questo manualmente.

Questo dà l'output che hai richiesto

<?xml version="1.0" encoding="utf-8"?> 
<csvImportSchema> 
    <payload> 
    <test>1</test> 
    <test2>2</test2> 
    <test3>3</test3> 
    <ean>1111111111</ean> 
    <productId>722619</productId> 
    </payload> 
</csvImportSchema> 
1

Questo XSLT dovrebbe fare il lavoro e utilizza modo più tag Copia e modelli. Forse non fare tutto in un xsl: template (la mia opinione).

<?xml version="1.0" encoding="UTF-8"?> 
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="/csvImportSchema"> 
     <xsl:copy> 
      <xsl:apply-templates select="*"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="csvImportSchema/payload/productId"> 
     <xsl:variable name="ean"> 
      <xsl:value-of select="../ean"/> 
     </xsl:variable> 
     <xsl:for-each select="../../product"> 
      <xsl:if test="ean = $ean"> 
       <productId><xsl:value-of select="article"/></productId> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="csvImportSchema/product"> 
     <!-- do not copy --> 
    </xsl:template> 

    <xsl:template match="csvImportSchema/payload"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
2

Un'osservazione sul codice. Non usare questo:

<xsl:variable name="ean"> 
    <xsl:value-of select="../ean"/> 
</xsl:variable> 

quando si poteva scrivere questo:

<xsl:variable name="ean" select="../ean"/> 

non solo è prolisso, è anche incredibilmente inefficiente: al posto del legame $ ean ad un nodo esistente, si estraggono il valore di stringa di un nodo esistente, formando un nodo di testo con quel valore di stringa, creando un nuovo albero di documenti XML e aggiungendo questo nodo di testo al contenuto di questo nuovo documento. (Una volta ho ottenuto un foglio di stile per eseguire 3 volte più velocemente eliminando questo costrutto orribile.)

+0

Grazie. Lo terrò a mente. – MMKD