<?xml version="1.0" encoding="utf-8"?>
<Report p1:schemaLocation="Customer details http://reportserver?%2fCustomer details&rs%3aFormat=XML&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列的参数选择(即他们可以选择列的顺序,他们可以选择一个特定的列是否包含在报告中,字体等等)。如前所述,每个列都有两个主要功能,即它们可以排序,也可以根据选择进行排序。
例如,从上面给出的xml格式的报告输出中,您将看到所有50列都存在于xml格式中,但我也包括了通常隐藏在报告中的额外字段。
col1包含在报告中,并被排序(seqID)作为csv文件的第二列。col2也包含在报告中,并作为csv文件的第一列排序。报告中没有包含col3,订单选择项为空,因此csv文件中没有包含col3。……同样,col50也包含在报告中,但在CSV文件中作为第三列排序。
我在这里的主要挑战是为"CSV"创建xslt文件,并将列按顺序选择,这些列是根据用户选择的。
转换后CSV文件中的输出如下所示:
Col2 Col1 Col50 Col4
... ... ... ....
任何创建这种xsl文件的好主意都是非常感谢的,我非常感谢您理解我的问题并试图在这方面帮助我。
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&rs%3aFormat=XML&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
:
- 我们使用XPath 1.0表达式:
__
substring($s1, string-length($s1) - string-length($s2) +1) = $s2
等价于XPath 2.0表达式:
ends-with($s1, $s2))
。2。合理使用<xsl:sort>
、substring()
、name()
和current()
。
。3。使用以下事实:字符串$s
当且仅当:
__
number($s) = number($s)
二世。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
Update: @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>	</xsl:text>
</xsl:for-each>
<xsl:text> </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