2009-04-06 7 views
1

Je ne suis pas sûr que le titre explique clairement mon problème, je vais essayer d'inclure autant de détails que je peux.Comment créer un fichier XML à partir d'une autre méta-donnée xml?

J'ai besoin de convertir au format xml sous format xml correctement formaté en utilisant Xslt 1, de sorte que je puisse le désérialiser en un type .net.

XML Source

  <ax21:result type="test.ws.Result"> 
       <ax21:columnNames>fileName</ax21:columnNames> 
       <ax21:columnNames>lockedState</ax21:columnNames> 
       <ax21:columnNames>currentLockOwner</ax21:columnNames> 
       <ax21:columnNames>UUID</ax21:columnNames> 
       <ax21:resultData>Test1.doc</ax21:resultData> 
       <ax21:resultData>true</ax21:resultData> 
       <ax21:resultData>analyst</ax21:resultData> 
       <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData> 
       <ax21:resultData>Test2.doc</ax21:resultData> 
       <ax21:resultData>false</ax21:resultData> 
       <ax21:resultData/> 
       <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData> 
       <ax21:resultData>Test3.doc</ax21:resultData> 
       <ax21:resultData>true</ax21:resultData> 
       <ax21:resultData>analyst</ax21:resultData> 
       <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData> 
       <ax21:resultData>Test4.doc</ax21:resultData> 
       <ax21:resultData>false</ax21:resultData> 
       <ax21:resultData/> 
       <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData> 
      </ax21:result> 

XML cible

<result> 
    <item> 
     <fileName>Test1.doc</fileName> 
     <lockedState>true</lockedState> 
     <currentLockOwner>analyst</currentLockOwner> 
     <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID> 
    </item> 
    <item> 
     <fileName>Test2.doc</fileName> 
     <lockedState>true</lockedState> 
     <currentLockOwner>analyst</currentLockOwner> 
     <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID> 
    </item> 
    <item> 
     <fileName>Test2.doc</fileName> 
     <lockedState>true</lockedState> 
     <currentLockOwner>analyst</currentLockOwner> 
     <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID> 
    </item> 
</result> 

Cela peut-il être fait en utilisant xslt? Si oui, pls poster un lien ou un échantillon xslt pour moi d'essayer.

J'utilise .net 2.0, C#, XSLT 1.0

+0

Cette source XML est au format XML uniquement. Il n'est certainement pas conforme à l'esprit de XML et donc toute solution utilisant XSL sera au mieux hackish. Si vous avez un contrôle sur le format de la source, je suggère fortement de le changer pour quelque chose de hiérarchique. – Welbog

+0

Il n'y a rien "hackish" dans la solution. XSLT peut être utilisé pour fournir des solutions élégantes à de nombreux problèmes «non traditionnels» ou apparemment «impossibles à résoudre». –

Répondre

3

C'est une assez courte et solution facile:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ax21="my:ax21" exclude-result-prefixes="ax21" 
> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:variable name="vCols" select="/*/ax21:columnNames"/> 
    <xsl:variable name="vNumCols" select="count($vCols)"/> 

    <xsl:template match="ax21:result"> 
     <result> 
      <xsl:apply-templates select= 
      "ax21:resultData[position() mod $vNumCols = 1]" 
      /> 
     </result> 
    </xsl:template> 

    <xsl:template match="ax21:resultData"> 
     <item> 
     <xsl:apply-templates mode="create" select= 
     "(.|following-sibling::ax21:resultData) 
           [not(position() > $vNumCols) ] 
     "/> 
     </item> 
    </xsl:template> 

    <xsl:template match="ax21:resultData" mode="create"> 
     <xsl:variable name="vPos" select="position()"/> 
    <xsl:element name="{$vCols[$vPos]}"> 
      <xsl:value-of select="."/> 
      <xsl:if test="not(text())"> 
      <xsl:value-of select= 
      "(.| preceding-sibling::ax21:resultData) 
         [position() mod $vNumCols = $vPos] 
          [text()] 
            [last()] 
      "/> 
      </xsl:if> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

Lorsque cette transformation est appliquée sur le document XML suivant:

<ax21:result type="test.ws.Result" 
xmlns:ax21="my:ax21" 
> 
    <ax21:columnNames>fileName</ax21:columnNames> 
    <ax21:columnNames>lockedState</ax21:columnNames> 
    <ax21:columnNames>currentLockOwner</ax21:columnNames> 
    <ax21:columnNames>UUID</ax21:columnNames> 
    <ax21:resultData>Test1.doc</ax21:resultData> 
    <ax21:resultData>true</ax21:resultData> 
    <ax21:resultData>analyst</ax21:resultData> 
    <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData> 
    <ax21:resultData>Test2.doc</ax21:resultData> 
    <ax21:resultData>false</ax21:resultData> 
    <ax21:resultData/> 
    <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData> 
    <ax21:resultData>Test3.doc</ax21:resultData> 
    <ax21:resultData>true</ax21:resultData> 
    <ax21:resultData>analyst</ax21:resultData> 
    <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData> 
    <ax21:resultData>Test4.doc</ax21:resultData> 
    <ax21:resultData>false</ax21:resultData> 
    <ax21:resultData/> 
    <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData> 
</ax21:result> 

le voulait le résultat est produit :

<result> 
    <item> 
     <fileName>Test1.doc</fileName> 
     <lockedState>true</lockedState> 
     <currentLockOwner>analyst</currentLockOwner> 
     <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID> 
    </item> 
    <item> 
     <fileName>Test2.doc</fileName> 
     <lockedState>false</lockedState> 
     <currentLockOwner>analyst</currentLockOwner> 
     <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID> 
    </item> 
    <item> 
     <fileName>Test3.doc</fileName> 
     <lockedState>true</lockedState> 
     <currentLockOwner>analyst</currentLockOwner> 
     <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID> 
    </item> 
    <item> 
     <fileName>Test4.doc</fileName> 
     <lockedState>false</lockedState> 
     <currentLockOwner>analyst</currentLockOwner> 
     <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID> 
    </item> 
</result> 

Explication:

  1. Pour plus de commodité les noms de colonnes et leur nombre sont collectées dans les variables globales $vCols et $vNumCols.

  2. Nous appliquons des modèles à chaque élément N 0 e ax21:resultData, où N mod $vNumCols = 1. Chaque élément commence un nouveau item.

  3. Chaque élément ax21:resultData qui sera le premier dans un item correspond à un modèle en mode "non-mode". Ceci crée simplement l'élément d'emballage item et applique à tous les éléments $ vNumCols ax21:resultData actuels un autre modèle - en mode "create".

  4. Le modèle en mode "create" crée simplement un élément, dont le nom est la valeur de l'élément de n-ième $vCols, où n est le position() du noeud courant() pour lequel le modèle est appliqué. Enfin, s'il arrive qu'aucune valeur n'a été fournie, nous obtenons (en ordre inverse) la dernière valeur non vide pour le même type d'élément.

+0

Merci Dimitre !!. Je ne savais pas si cela pouvait être résolu par XSLT, je l'ai seulement posté ici pour avoir votre avis sur ce problème. Merci encore. –

+0

Sur une autre note, la structure xml a changé depuis que j'ai posté ceci et c'est plus correct et a un index comme suggéré par Marc. Votre réponse ci-dessus va m'aider à créer le modèle pour le nouveau. Merci encore. –

+0

@gk Vous êtes les bienvenus! :) Il y a beaucoup de problèmes qui semblent même "plus durs" que cela, qui peuvent être résolus d'une manière élégante en XSLT. Dans une courte période j'ai résolu 60 problèmes de Project Euler, et la solution à l'un de ces problèmes (qui ne pouvait pas être faite avec un stylo et un crayon) a été implémentée dans XSLT. –

0

qui va être vraiment difficile, sinon impossible, pour le gérer correctement et de manière fiable.

Le problème est: il n'y a aucune indication d'un indice ou d'un type sur le nombre et les noeuds à ce que leur type/position - vous avez plus ou moins deviner ...

Ce serait une autre histoire si au moins avait un attribut supplémentaire, quelque chose comme et ainsi de suite - de cette façon, on pourrait être en mesure de les associer d'une manière ou d'une autre.

Y a-t-il une chance que vous puissiez "masser" un peu les données d'origine? Sinon, je dirais probablement que vous devrez le charger en C# et l'analyser et faire beaucoup de traitement manuel pour obtenir ce que vous voulez.

Marc

+0

Pas difficile du tout! Et certainement, absolument possible. XSLT est un langage puissant qui fournit des solutions élégantes à de tels problèmes. Il suffit de penser :) –

+0

J'avais des pensées similaires, j'attendais la réponse de Dimitre. Quoi qu'il en soit, j'ai travaillé avec l'autre équipe pour obtenir le xml dans une structure plus significative. –

+0

Les gars, si vous voulez voir des solutions XSLT élégantes à certains problèmes vraiment difficiles, regardez ici: http://stackoverflow.com/questions/693596/elegant-examples-of-xslt/693953#693953 –

Questions connexes