2009-07-27 18 views
5

que desea traducir un archivo XML con datos como los siguientes:XSLT en SSRS informe

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

Los datos que me interesa es los atributos y sus valores en cada Details1. El problema es que estos atributos no necesariamente van a ser los mismos en todos los archivos XML que quiero traducir, y quiero un XSL propósito general que pudiera manejar tales Details1 como éstos:

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

estos diferentes Details1 no lo haría ocurren en el mismo archivo XML de origen, sino en diferentes archivos. Sin embargo, me gustaría usar el mismo XSL en cada uno.

Estaba pensando que necesitaba algo como <xsl:value-of select="@attribute_name"/>, pero ¿qué pongo para @attribute_name cuando no sé de antemano qué atributos habrá? Además, ¿cómo capturo el nombre del atributo? Me gustaría hacer explotar la fuente XML arriba para algo como:

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

Editar: gracias por las respuestas! Estoy teniendo problemas para conseguir más de la siguiente salida, sin embargo:

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

He intentado tanto de Lavinio y respuestas de Jörn Horstmann, así como tratar de combinar los dos. Corro este comando:

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

Creo que algo que está en el camino es un namespace en el archivo de entrada:

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

Respuesta

4

Hubo una mayor dificultad debido al espacio de nombres de Microsoft SQL Reporting Services 2008 que formaba parte del XML de entrada. No me di cuenta al principio que <Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport"> era una línea tan importante. Gracias a Pavel Minaev por el namespace comment. La siguiente XSL trabajó para extraer los datos que quería:

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

Creo que voy a tratar de limpiar esto para usar el estilo apply-templates que lavinio sugeridos. Gracias también a Jörn Horstmann por el código select="@*" en for-each loops. Sería interesante averiguar por qué los informes de Reporting Services se descargan inicialmente con el valor xmlns establecido en el nombre del informe, y no en schema URL.

Continuaré actualizando esta respuesta a medida que refino este XSL.

Editar: aquí es una versión de espacio de nombres independiente del puesto, para cada informe diferente de Reporting Services, hay al parecer habrá un espacio de nombres diferentes:

<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

Usted puede utilizar "@*" para referirse a todos los atributos, como estos ejemplos:

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

El <xsl:element name=""> constructo se puede utilizar para crear un nuevo elemento con un nombre arbitrario, y las funciones name() o local-name() devolverá el nombre de un atributo específico.

para hacer lo que desea, pruebe algo en este sentido:

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

¿Proporciona esta transformación el resultado deseado?

<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

Esto se traduce en un archivo XML con casi tantas líneas como el original, XML de entrada, pero con todos ellos en blanco, guarde la primera línea que contenga ''. –

+0

Resulta que recibí líneas en blanco en lugar de los datos que quería debido a un problema de espacio de nombres; pregunta actualizada, agregué mi propia respuesta. –

0

otra manera de escribir la respuesta de Jörn Horstmann (si es que tiene que hacer esto con details1, Details2, y así sucesivamente ...) Sería:

<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

Probablemente la forma más sencilla de hacerlo:

<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

No realmente, esto simplemente copia los elementos tal como están, y la pregunta es sobre la traducción de atributos a elementos. –

3

para resolver el problema de espacio de nombres (para ambas respuestas), agregar una declaración de espacio con un prefijo a su XLST:

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

y luego usarlo en todas sus expresiones XPath para calificar los elementos, por ejemplo:

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