2009-07-27 185 views
5

我想通過類似以下的數據轉換爲XML文件:XSLT在SSRS報告

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

我感興趣的數據是各Details1的屬性和它們的值。問題是,這些屬性並不一定要在我要翻譯的每一個XML文件是相同的,我希望有一個通用的XSL,可以處理這樣Details1這些:

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

這些不同Details1不會發生在同一個源XML文件中,而是出現在不同的文件中。不過,我想在每個XSL上使用相同的XSL。

我在想我需要像<xsl:value-of select="@attribute_name"/>這樣的東西,但是當我事先不知道會有什麼屬性時,我會爲@attribute_name放什麼東西?另外,如何捕獲屬性名稱?我想爆炸源XML以上類似:

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

編輯:感謝您的答覆!我遇到了麻煩比下面的輸出更多,但是:

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

我都試過lavinio的和喬恩HORSTMANN的答案,以及試圖將兩者結合起來。我運行此命令:

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

我認爲東西是獲得的方式是在輸入文件中的namespace

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

回答

4

由於Microsoft SQL Reporting Services 2008名稱空間是輸入XML的一部分,因此增加了難度。起初我並沒有意識到<Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport">是如此重要的一條線。感謝Pavel Minaev的namespace comment。以下XSL工作來提取我想要的數據:

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

我想我會嘗試清理它使用apply-templates風格lavinio建議。對於for-each循環中的select="@*"代碼,還要感謝Jörn Horstmann。找出爲什麼Reporting Services報告最初傾倒的原因是xmlns的值設置爲報告的名稱,而不是schema URL,這很有趣。

我會繼續更新這個答案,因爲我改進了這個XSL。

編輯:這裏有一個命名空間無關的版本,因爲,從Reporting Services的每一個不同的報告,會有很明顯是不同的命名空間:

<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

您可以使用"@*"指所有的屬性,如這些例子:

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

<xsl:element name="">構建體可用於具有任意名稱創建一個新的元件,所述功能name()local-name()將返回一個特定屬性的名稱。

做你想做的,可以嘗試沿着這些路線的東西:

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

這是否轉化給你想要的結果呢?

<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

這將導致一個XML文件幾乎一樣多的行原始的,輸入XML,但全部爲空,保存第一行包含`<?xml version =「1.0」encoding =「utf-8」?>`。 – 2009-07-28 16:02:28

+0

原來,由於名稱空間問題,我得到了一個空行而不是我想要的數據;更新的問題,添加了我自己的答案。 – 2009-07-28 17:17:23

0

另一種方式來寫喬恩HORSTMANN的回答(如果你需要點評詳情,Details2要做到這一點,等等...)將是:

<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

可能做到這一點最簡單的方法:

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

爲了解決命名空間問題(兩個答案),增加一個命名空間聲明有前綴您XLST:

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

,然後用它在你的所有XPath表達式資格元素,例如:

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