2009-07-27 20 views
5

Je veux traduire un fichier XML avec des données telles que les suivantes:XSLT sur SSRS rapport

<FlatData> 
    <Details1_Collection> 
     <Details1 Customer1="Customer" Total1="3" /> 
     ... 
    </Details1_Collection> 
</FlatData> 

Les données que je suis intéressé par ce sont les attributs et leurs valeurs dans chaque Details1. Le problème est que ces attributs ne vont pas nécessairement être le même dans chaque fichier XML que je veux traduire, et je veux un but général XSL qui pourrait gérer une telle Details1 comme ceux-ci:

<Details1 Customer1="Customer" Total1="3" /> 
<Details1 Name="Jim" Age="14" Weight="180" /> 
<Details1 Date="2009-07-27" Range="1-5" Option1="True" /> 

Ces différentes Details1 ne serait pas se produire dans le même fichier XML source, mais plutôt dans des fichiers différents. Cependant, je voudrais utiliser le même XSL sur chacun.

Je pensais que j'avais besoin de quelque chose comme <xsl:value-of select="@attribute_name"/> mais qu'est-ce que je mets pour @attribute_name quand je ne sais pas à l'avance quels attributs il y aura? De même, comment capturer le nom de l'attribut? Je voudrais faire exploser le XML source ci-dessus à quelque chose comme:

<Details1> 
    <Customer1>Customer</Customer1> 
    <Total1>3</Total1> 
</Details1> 

Edit: merci pour les réponses! Je vais avoir du mal à obtenir plus que la sortie suivante, cependant:

<?xml version="1.0" encoding="UTF-8"?> 
<FlatData> 
<Details1_Collection></Details1_Collection> 
</FlatData> 

J'ai essayé les deux années Lavinio et les réponses de Jörn Horstmann, ainsi que d'essayer de combiner les deux. Je lance cette commande:

msxsl.exe -o output.xml input.xml transform.xsl 

Je pense que quelque chose qui de prendre le chemin est un namespace dans le fichier d'entrée:

<Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport"> 

Répondre

4

Il y avait une difficulté accrue en raison de l'espace de noms Microsoft SQL Reporting Services 2008 qui faisait partie du code XML d'entrée. Je n'ai pas réalisé au début que <Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport"> était une ligne si importante. Merci à Pavel Minaev pour le namespace comment. Le suivant a travaillé pour XSL extraire les données que je voulais:

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

    <xsl:template match="/"> 
    <xsl:for-each select="a:Report/a:FlatData/a:Details1_Collection/a:Details1"> 
     <xsl:element name="{name(.)}"> 
     <xsl:for-each select="@*"> 
      <xsl:element name="{name(.)}"> 
      <xsl:value-of select="."/> 
      </xsl:element> 
     </xsl:for-each> 
     </xsl:element> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

Je pense que je vais essayer de nettoyer ce pour utiliser le style apply-templates qui lavinio suggéré. Merci également à Jörn Horstmann pour le code select="@*" dans les boucles for-each. Il serait intéressant de comprendre pourquoi les rapports Reporting Services sont initialement vidés avec la valeur xmlns définie pour le nom du rapport, et non schema URL.

Je vais continuer à mettre à jour cette réponse que j'affine cette XSL.

Edit: est ici une version d'espace de nom agnostique puisque, pour chaque rapport différent de Reporting Services, il y aura apparemment un espace de noms différent:

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

    <xsl:template match="/"> 
    <xsl:for-each select="*[local-name()='Report']/*[local-name()='FlatData']/*[local-name()='Details1_Collection']/*[local-name()='Details1']"> 
     <Details> 
     <xsl:for-each select="@*"> 
      <xsl:element name="{name(.)}"> 
      <xsl:value-of select="."/> 
      </xsl:element> 
     </xsl:for-each> 
     </Details> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 
3

Vous pouvez utiliser "@*" pour désigner tous les attributs, comme ces exemples:

  • <xsl:value-of select="@*"/>
  • <xsl:apply-templates select="@*"/>
  • <xsl:template match="@*">

La construction <xsl:element name=""> peut être utilisé pour créer un nouvel élément avec un nom arbitraire, et les fonctions name() ou local-name() retourne le nom d'un attribut spécifique.

Pour faire ce que vous voulez, essayez quelque chose le long de ces lignes:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="/"> 
     <FlatData> 
      <Details1_Collection> 
       <xsl:apply-templates select="FlatData/Details1_Collection/Details1"/> 
      </Details1_Collection> 
     </FlatData> 
    </xsl:template> 
    <xsl:template match="Details1"> 
     <Details1> 
      <xsl:apply-templates select="@*"/> 
     </Details1> 
    </xsl:template> 
    <xsl:template match="@*"> 
     <xsl:element name="{name()}"> 
      <xsl:value-of select="."/> 
     </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 
2

Est-ce que cette transformation donne le résultat que vous voulez?

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

    <xsl:output method="xml" indent="yes" encoding="utf-8" /> 

    <xsl:template match="//Details1"> 
     <Details1> 
      <xsl:for-each select="@*"> 
       <xsl:element name="{name(.)}"><xsl:value-of select="." /></xsl:element> 
      </xsl:for-each> 
     </Details1> 
    </xsl:template> 

</xsl:stylesheet> 
+0

Il en résulte un fichier XML avec presque autant de lignes que l'original, XML d'entrée, mais avec tous vide la première ligne contenant '. –

+0

Il s'avère que j'ai eu des lignes vides au lieu des données que je voulais à cause d'un problème d'espace de noms; question mise à jour, ajouté ma propre réponse. –

0

une autre façon d'écrire la réponse de Jörn Horstmann (si vous avez besoin de le faire avec Details1, Details2, et ainsi de suite ...) Serait:

<xsl:template match="//Details1 | //Details2 | //whatever"> 
    <xsl:copy> 
    <xsl:apply-templates select="@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="@*"> 
    <xsl:element name="{name(.)}"> 
    <xsl:value-of select="." /> 
    </xsl:element> 
</xsl:template> 
0

Probablement la façon la plus simple de le faire:

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

    <xsl:template match="/"> 
    <FlatData> 
     <xsl:copy-of select="//Details1" /> 
    </FlatData> 
    </xsl:template> 
</xsl:stylesheet> 
+1

Pas vraiment - cela copie juste les éléments tels quels, et la question est de traduire les attributs en éléments. –

3

Pour résoudre le problème d'espace de noms (pour les deux réponses), ajoutez une déclaration d'espace de noms avec un préfixe à votre XLST:

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

et ensuite l'utiliser dans toutes vos expressions XPath pour qualifier les éléments, par exemple:

<xsl:template match="//r:Details1">