2011-04-24 6 views
0

J'essaie de prendre un fichier CSV en entrée et de le transformer en XML. Je suis nouveau à XSLT et je l'ai trouvé un moyen de convertir un fichier CSV en XML (en utilisant un exemple de Andrew Welch) comme ceci:Transformation en deux phases utilisant XSLT 2.0

fichier CSV d'entrée:

car manufacturer,model,color,price,inventory 
subaru,outback,blue,23195,54 
subaru,forester,silver,20495,23 

Et mon XML de sortie serait :

<?xml version="1.0" encoding="UTF-8"?> 
<rows> 
    <row> 
     <column name="car manufacturer">subaru</column> 
     <column name="model">outback</column> 
     <column name="color">blue</column> 
     <column name="price">23195</column> 
     <column name="inventory">54</column> 
    </row> 
    <row> 
     <column name="car manufacturer">subaru</column> 
     <column name="model">forester</column> 
     <column name="color">silver</column> 
     <column name="price">20495</column> 
     <column name="inventory">23</column> 
    </row> 
</rows> 

Ma sortie désirée est en fait quelque chose de similaire à:

<stock> 
    <model> 
     <car>subaru outback</car> 
     <color>blue</color> 
     <price>23195</price> 
     <inventory>54</inventory> 
    </model> 
    <model> 
     <car>subaru forester</car> 
     <color>silver</color> 
     <price>20495</price> 
     <inventory>23</inventory> 
    </model> 
</stock> 

Ce que je lis est qu'il serait préférable de faire une transformation en deux phases. Le CSV en XML est fait en utilisant XSLT 2.0, donc je pensais que la transformation en deux phases serait faite en utilisant cela aussi sans utiliser la fonction d'ensemble de nœuds. Par conséquent, la première phase consistera à prendre le fichier CSV d'origine en entrée, puis à sortir le fichier XML intermédiaire illustré ci-dessus. Prenez ensuite ce fichier XML intermédiaire et transmettez-le à une autre transformation pour obtenir la sortie souhaitée.

Quelqu'un peut-il aider à la réalisation de la transformation en deux phases? J'ai du mal à passer la sortie de la première phase en entrée de la phase 2?

J'ai quelque chose comme ça jusqu'à présent:

<xsl:import href="csv2xml.xsl"/> 
<xsl:output method="xml" indent="yes" /> 

<xsl:variable name="intermediate"> 
    <xsl:apply-templates select="/" mode="csv2xml"/> 
</xsl:variable> 

<xsl:template match="rows" name="main"> 

**[This is what I'm having trouble with]** 

</xsl:template> 
+2

Cela semble être une utilisation inefficace de XSLT. Vous pouvez analyser le fichier CSV directement et générer le fichier XML directement dans un langage procédural standard (par exemple, Perl, Python, etc.). XSLT n'est pas le meilleur outil pour analyser des données non-XML. – ewh

Répondre

2

Ce XSLT 2.0 stylesheet:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/"> 
     <xsl:variable name="vLines" 
     select="tokenize(unparsed-text('test.txt'),'(&#xD;)?&#xA;')"/> 
     <xsl:variable name="vHeaders" 
     select="tokenize($vLines[1],',')"/> 
     <stock> 
      <xsl:for-each select="$vLines[position()!=1]"> 
       <model> 
        <xsl:variable name="vColumns" select="tokenize(.,',')"/> 
        <xsl:for-each select="$vColumns"> 
         <xsl:variable name="vPosition" select="position()"/> 
         <xsl:variable name="vHeader" 
         select="$vHeaders[$vPosition]"/> 
         <xsl:choose> 
          <xsl:when test="$vHeader = 'car manufacturer'"> 
           <column name="car"> 
            <xsl:value-of 
            select="(.,$vColumns[ 
                index-of($vHeaders,'model') 
               ])"/> 
           </column> 
          </xsl:when> 
          <xsl:when test="$vHeader = 'model'"/> 
          <xsl:otherwise> 
           <column name="{$vHeader}"> 
            <xsl:value-of select="."/> 
           </column> 
          </xsl:otherwise> 
         </xsl:choose> 
        </xsl:for-each> 
       </model> 
      </xsl:for-each> 
     </stock> 
    </xsl:template> 
</xsl:stylesheet> 

Sortie:

<stock> 
    <model> 
     <column name="car">subaru outback</column> 
     <column name="color">blue</column> 
     <column name="price">23195</column> 
     <column name="inventory">54</column> 
    </model> 
    <model> 
     <column name="car">subaru forester</column> 
     <column name="color">silver</column> 
     <column name="price">20495</column> 
     <column name="inventory">23</column> 
    </model> 
</stock> 

Remarque: Dans XSLT 3.0, vous pourrez appliquer des modèles à des éléments en général.

EDIT: noms corrects.

+0

Merci, @Alejandro.J'ai pu apprendre de votre réponse donnée pour obtenir le résultat que je veux. – eyedrop

+1

@eyedrop: Votre question actuelle est: "Quelqu'un peut-il m'aider sur la façon dont la transformation en deux phases peut être effectuée? J'ai du mal à passer la sortie de la phase 1 en entrée de la phase 2?" Réponse @ Alejandro ne répond pas à la question réelle - il fournit une solution pour la phase1. La réponse qui répond exactement à votre question est celle de @ Michael-Kay. S'il vous plaît, pensez à accepter sa réponse! –

7

Je ne vois aucune raison pour laquelle cette transformation a besoin de deux phases - sauf peut-être pour vous permettre de réutiliser le code existant pour l'un des les phases.

Toutefois, lorsque vous avez besoin de deux phases, le modèle général est:

<xsl:template match="/"> 
    <xsl:variable name="phase-1-result"> 
    <xsl:apply-templates select="/" mode="phase-1"/> 
    </xsl:variable> 
    <xsl:apply-templates select="$phase-1-result" mode="phase-2"/> 
</xsl:template> 

avec les règles de modèle pour la phase 1 et la phase 2 (et leurs apply-templates appels) tous étant en phase 1 Mode ou phase-2 respectivement.