2009-07-27 3 views
5

Voglio tradurre un file XML con i dati come il seguente:XSLT su SSRS relazione

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

I dati Sono interessato è gli attributi ei loro valori in ogni Details1. Il problema è che questi attributi non sono necessariamente andando essere lo stesso in ogni file XML che voglio tradurre, e voglio un XSL general purpose in grado di gestire tale Details1 come questi:

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

questi diversi Details1 no si verificano nello stesso file XML di origine, ma piuttosto in file diversi. Tuttavia, mi piacerebbe usare lo stesso XSL su ciascuno.

Stavo pensando che avevo bisogno di qualcosa come <xsl:value-of select="@attribute_name"/> ma cosa devo mettere per @attribute_name quando non so in anticipo quali attributi ci saranno? Inoltre, come posso acquisire il nome dell'attributo? Vorrei far esplodere la XML di origine sopra a qualcosa di simile:

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

Modifica: Grazie per le risposte! Sto avendo difficoltà a raggiungere più del seguente output, però:

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

Ho provato entrambe le Lavinio di e risposte di Jörn Horstmann, così come il tentativo di combinare le due cose. Ho eseguito questo comando:

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

penso che qualcosa che sta ottenendo nel senso è una namespace nel file di input:

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

risposta

4

Si è verificato un aumento della difficoltà a causa dello spazio dei nomi di Microsoft SQL Reporting Services 2008 che faceva parte dell'XML di input. All'inizio non mi ero reso conto che il numero <Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport"> fosse una linea così importante. Grazie a Pavel Minaev per lo namespace comment. Il seguente XSL ha lavorato per estrarre i dati che volevo:

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

Credo che cercherò di pulire questo fino a utilizzare lo stile apply-templates che lavinio suggerito. Grazie anche a Jörn Horstmann per il codice select="@*" nei loop for-each. Sarebbe interessante capire perché i report di Reporting Services vengono scaricati inizialmente con il valore xmlns impostato sul nome del report e non su schema URL.

Continuerò ad aggiornare questa risposta mentre perfeziono questo XSL.

Edit: Ecco una versione namespace-agnostic dal momento che, per ogni rapporto diverso da Reporting Services, ci sarà a quanto pare sarà uno spazio dei nomi diverso:

<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

È possibile utilizzare "@*" per riferirsi a tutti gli attributi, come questi esempi:

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

Il <xsl:element name=""> costrutto può essere utilizzato per creare un nuovo elemento con un nome arbitrario, e le funzioni name() o local-name() restituirà il nome di un attributo specifico.

di fare ciò che si vuole, provare qualcosa in queste righe:

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

Questo Trasformazione dare il risultato desiderato?

<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

Ciò si traduce in un file XML con quasi altrettanti linee come l'originale, l'XML di input, ma con tutti gli spazi vuoti salva la prima riga contenente ''. –

+0

Risulta che ho ottenuto una riga vuota invece dei dati che volevo a causa di un problema di namespace; domanda aggiornata, aggiunta la mia risposta. –

0

un altro modo per scrivere la risposta di Jörn Horstmann (se avete bisogno di fare questo con Dettagli1, Details2, e così via ...) Sarebbe:

<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

Probabilmente il modo più semplice per farlo:

<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

Non proprio - questo copia solo gli elementi così come sono, e la domanda riguarda la traduzione di attributi in elementi. –

3

per risolvere il problema dello spazio dei nomi (per entrambe le risposte), aggiungere una dichiarazione di namespace con un prefisso al tuo XLST:

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

e poi utilizzarlo in tutte le vostre espressioni XPath per qualificare gli elementi, ad esempio:

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