如何对xslt中的元素(列)进行排序以将xml文件转换为csv格式

时间:2011-09-25 01:40:18

标签: xslt xslt-2.0 xslt-1.0 xslcompiledtransform

<?xml version="1.0" encoding="utf-8"?>
<Report p1:schemaLocation="Customer details  http://reportserver?%2fCustomer details&amp;rs%3aFormat=XML&amp;rc%3aSchema=True" Name="Customer details" xmlns:p1="http://www.w3.org/2001/XMLSchema-instance" xmlns="Customer details">
  <table2>
   <Detail_Collection>
         <Detail Col1="aaa" col1_SeqID="2"  col1_Include="1"
                 Col2="aaa" col2_SeqID="1"  col2_Include="1"
                 Col3="aaa" col3_SeqID=""  col3_Include="0"
                 Col4="aaa" col4_SeqID="4"  col4_Include="1"
                 Col5="aaa" col5_SeqID=""  col5_Include="0"
                 ... ... ...
                 ... ... ...
                 ... ... ...
                 Col50="aaa" col50_SeqID="3"  col50_Include="1"
                 />
   <Detail_Collection>
</table2>
</Report>

上面的XML由SSRS为RDL文件生成。我想使用XSLT(自定义格式)将上述xml文件转换为CSV格式。 RDL文件(SSRS报告)非常简单,有50列,并根据用户界面上的用户选择显示所有列的数据。 用户界面已经获得了所有50列的参数选择(即,他们可以选择列的顺序,他们可以选择要包含在报告中的特定列,fontstyle等...)。如上所述,每列有两个主要功能,即它们可以根据选择进行排序和排序。

例如,从报告输出中,即上面给出的xml格式,您将看到xml格式中存在的所有50列,但我还包括通常隐藏在报告上的额外fiedls。

col1包含在报告中,并按顺序排列(seqID)作为csv文件的第2列。 col2也包含在报告中,并作为csv文件的第1列排序。 col3不包含在报告中,并且订单选择为空,因此csv文件中不包含此内容。 ... ... 同样明智的是col50包含在报告中,但是在csv文件的第3列中排序。

我的主要挑战是为“CSV”创建xslt文件,并将列放在按用户选择的顺序选择中。

转换后CSV文件中的输出如下所示:

Col2    Col1    Col50   Col4
 ...  ...       ...     ....

非常感谢创建这种xsl文件的任何好主意,我非常感谢你理解我的问题,并在这方面帮助我。

1 个答案:

答案 0 :(得分:1)

<强>予。这个XSLT 1.0转换:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:c="Customer details">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="c:Detail">
     <xsl:apply-templates select=
      "@*[substring(name(), string-length(name())-5)
         = '_SeqID'
        and
          number(.) = number(.)
          ]
     ">
      <xsl:sort data-type="number"/>
     </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:if test="not(position()=1)">,</xsl:if>
  <xsl:value-of select=
    "../@*
       [name()
       =
        concat('Col',substring-before(substring(name(current()),4),'_'))
        ]"/>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档(提供的文档,格式正确且无歧义):

<Report
p1:schemaLocation="Customer details  http://reportserver?%2fCustomer details&amp;rs%3aFormat=XML&amp;rc%3aSchema=True"
Name="Customer details"
xmlns:p1="http://www.w3.org/2001/XMLSchema-instance"
xmlns="Customer details">
    <table2>
        <Detail_Collection>
            <Detail Col1="aaa1" col1_SeqID="2"  col1_Include="1"
            Col2="aaa2" col2_SeqID="1"  col2_Include="1"
            Col3="aaa3" col3_SeqID=""  col3_Include="0"
            Col4="aaa4" col4_SeqID="4"  col4_Include="1"
            Col5="aaa5" col5_SeqID=""  col5_Include="0"
            Col50="aaa50" col50_SeqID="3"  col50_Include="1"
            />
        </Detail_Collection>
    </table2>
</Report>

生成想要的正确结果

aaa2,aaa1,aaa50,aaa4

<强>解释

  1. 我们使用XPath 1.0表达式:
  2. __

    substring($s1, string-length($s1) - string-length($s2) +1) = $s2
    

    等同于XPath 2.0表达式:

    ends-with($s1, $s2))
    

    0.2。适当使用<xsl:sort>substring()name()current()

    0.3。使用以下事实:当且仅当:

    时,字符串$s可以转换为数字

    __

    number($s) = number($s)
    

    <强> II。 XSLT 2.0解决方案:

    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:c="Customer details">
     <xsl:output method="text"/>
     <xsl:strip-space elements="*"/>    
    
     <xsl:template match="c:Detail">
             <xsl:apply-templates select=
              "@*[ends-with(name(),'_SeqID')
                and . castable as xs:integer]">
              <xsl:sort  select="xs:integer(.)"/>
             </xsl:apply-templates>
     </xsl:template>
     <xsl:template match="@*">
          <xsl:if test="not(position()=1)">,</xsl:if>
          <xsl:value-of select=
            "../@*
               [name()
               eq
                concat('Col',translate(name(current()),'col_SeqID',''))]"/>
     </xsl:template>
    </xsl:stylesheet>
    

    将此转换应用于同一XML文档(上图)时,会生成相同的正确结果

    aaa2,aaa1,aaa50,aaa4
    

    更新:@desi已要求也应生成标题。

    以下是更新的XSLT 1.0转换(如图所示,@ desi仅限于使用XSLT 1.0),这样做:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:c="Customer details">
     <xsl:output method="text"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:template match="c:Detail">
    
         <xsl:for-each select=
          "@*[substring(name(), string-length(name())-5)
             = '_SeqID'
            and
              number(.) = number(.)
              ]
            ">
            <xsl:sort data-type="number"/>
    
           <xsl:value-of select=
           "concat('Col',
                   substring-before(substring(name(current()),4),
                                    '_')
                   )
           "/>
    
              <xsl:text>&#9;</xsl:text>
         </xsl:for-each>
         <xsl:text>&#10;</xsl:text>
    
         <xsl:apply-templates select=
          "@*[substring(name(), string-length(name())-5)
             = '_SeqID'
            and
              number(.) = number(.)
              ]
         ">
          <xsl:sort data-type="number"/>
         </xsl:apply-templates>
     </xsl:template>
    
     <xsl:template match="@*">
      <xsl:if test="not(position()=1)">,</xsl:if>
      <xsl:value-of select=
        "../@*
           [name()
           =
            concat('Col',substring-before(substring(name(current()),4),'_'))
            ]"/>
     </xsl:template>
    </xsl:stylesheet>
    

    当在同一个XML文档(上面)上应用此转换时,会生成所需的正确结果

    Col2    Col1    Col50   Col4    
    aaa2,aaa1,aaa50,aaa4