我有一个 RDL 报告文件,我想以某种方式“运行”报告并获取将用于填充报告的数据集。我想要做的是从用于填充报告的数据中提取原始数据,而不是实际向用户显示报告。这可能吗?
3 回答
如果我了解您想要做什么,那么是的,这是可能的,但这有点痛苦。我为 Report Builder 2.0 报表的各种快照(在报表管理器中拍摄)执行此操作。
如果您使用报表服务器的内置 Web 服务,则可以以编程方式生成报表。请参阅ReportExecutionService.Render 方法对于一些示例代码(请注意,即使使用 SQL Server 2008,我也使用 ReportExecution2005 Web 服务)。您可以将报表呈现为各种格式,例如 XML、MHTML 或 PDF,然后尝试从中提取数据。您应该将您关心的数据表添加到报表中,通过将其 Visibility 更改为 Hide 来隐藏该表,但将其 DataElementOutput 属性设置为 Output 以便无论何时呈现报表,都会包含该表。给表格一些独特的名称(例如,将“Tablix1”替换为“FlatData”)。然后,您可以将报告呈现为 XML 格式并使用 XSLT 仅提取该表中的行。这是我之前用来从呈现的 Report Builder 2.0 报表中提取数据的一些 XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>
<xsl:variable name="reportID" select="*[local-name()='Report']/@Name"/>
<!-- Uppercase and lowercase alphabets for case-insensitive string comparisons -->
<xsl:variable name="up" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="lo" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:template match="/">
<xsl:element name="ContainerElementOfMyData">
<xsl:attribute name="ReportID">
<xsl:value-of select="$reportID"/>
</xsl:attribute>
<xsl:for-each select="*[local-name()='Report']/*[local-name()='FlatData']">
<!-- If the FlatData node has attributes on its tag, insert all of those
attributes in a single node -->
<xsl:if test="count(@*) > 0">
<MyNode>
<xsl:for-each select="@*">
<xsl:variable name="parentAttrName" select="name(.)"/>
<xsl:element name="{$parentAttrName}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</MyNode>
</xsl:if>
<!-- Go through each tag in FlatData that starts with 'Details' -->
<xsl:for-each select="//*[substring(local-name(), 1, 7)='Details']">
<xsl:if test="count(@*) > 0">
<MyNode>
<!-- For each attribute of the Details tag: -->
<xsl:for-each select="@*">
<xsl:variable name="attrName" select="name(.)"/>
<xsl:variable name="lowerAttrName" select="translate($attrName,$up,$lo)"/>
<xsl:variable name="attrValue" select="."/>
<!-- Write the attribute name as its own tag -->
<xsl:element name="{$attrName}">
<xsl:choose>
<xsl:when test="$attrValue = ''">
<!-- Do nothing because no value to output and we don't want empty CDATA tags -->
</xsl:when>
<!-- When field might have HTML tags, we want to wrap it in CDATA tags: -->
<xsl:when test="$lowerAttrName = 'my_first_text_field' or $lowerAttrName = 'my_other_text_field'">
<xsl:text disable-output-escaping="yes"><![CDATA[<![CDATA[]]></xsl:text>
<xsl:value-of select="$attrValue"/>
<xsl:text disable-output-escaping="yes">]]</xsl:text>
<xsl:text disable-output-escaping="yes">></xsl:text>
</xsl:when>
<!-- When field will not have HTML tags, just output its value as normal -->
<xsl:otherwise>
<xsl:value-of select="$attrValue"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:for-each>
</MyNode>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:element><!--End of ContainerElementOfMyData-->
</xsl:template>
</xsl:stylesheet>
请注意,此 XSLT 取决于您将报表中隐藏的数据表命名为“FlatData”。如果您知道报告中的某些数据将包含 HTML 标记或其他如果放置在两个 XML 标记之间将不是有效 XML 的内容,请更改上面的 XSLT 以将该数据包装在 CDATA 标记中(例如,替换my_first_text_field
为字段名称其值将需要 CDATA 标记)。
将此 XSLT 应用于报表的呈现 XML 版本将生成更多 XML,这一次只包含您关心的报表中的数据。仅使用呈现的 XML 版本的报告的问题在于它包含所有图表、外观信息等,而不仅仅是您的数据。尝试以 XML 格式呈现您的一份报告并查看源代码;它有各种你可能不想要的疯狂。
对于将 XSLT 转换应用于 XML 的命令行工具,我推荐xalan。这是一个示例用法:
PS C:\Program Files\xalan-j_2_7_0> java org.apache.xalan.xslt.Process -IN rdl_rendered_to_xml.xml -XSL xsl_shown_above.xsl -OUT transformed.xml
生成的transformed.xml 将具有如下格式:
<?xml version="1.0" encoding="utf-8"?>
<ContainerElementOfMyData ReportID="MyReportName">
<MyNode>
<Key1>Value 1</Key1>
<Key2>Second value of your data</Key2>
</MyNode>
</ContainerElementOfMyData>
正如 Sarah Vessels 在她的回答中已经提到的那样,您可以推送报表服务器以多种格式呈现数据,也许 EXCEL 是不错的选择,这取决于您的报表设计的复杂性。 我问了类似的问题,经过许多托盘后,我最终在 Mssql 中使用了 #TempTaples,在报告被撕裂之前,它被疯狂了,在我看来,报告服务器是作业处理的最后一个实例,所有数据和存储都应该在后端完成呈现报告
这是一个有趣的问题。当我不得不解决它时(用于 rdl 文件的单元测试),我编写了一个简单的 xml 解析器,它将从 rdl 文件中提取 sql 语句并执行它。这很简单,但如果你的语句有很多参数,当然会变得更复杂。但是,文件中也提供了参数信息,因此您应该能够编写通用解决方案(但您当然需要为参数提供值)。