如何从 RDL 文件获取要填充的数据集?

发布于 2024-08-28 18:30:01 字数 92 浏览 11 评论 0原文

我有一个 RDL 报告文件,我想以某种方式“运行”该报告并获取用于填充报告的数据集。我想要做的是从用于填充报告的数据中获取原始数据提取,而不实际向用户显示报告。这可能吗?

I have an RDL report file and I would like to somehow "run" the report and get the dataset that would be used to fill the report. What I'm trying to do is get a raw data extract from the data that would be used to fill the report, without actually showing the report to the user. Is this possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

十级心震 2024-09-04 18:30:01

如果我明白你想做什么,那么是的,这是可能的,但这有点痛苦。我对 Report Builder 2.0 报告的各种快照(如在报告管理器中拍摄的)执行了此操作。

如果您使用报表服务器的内置 Web 服务,则可以通过编程方式生成报表。有关一些示例代码,请参阅 ReportExecutionService.Render 方法(请注意,即使使用 SQL Server 2008,我也使用 ReportExecution2005 Web 服务。您可以将报告呈现为各种格式,例如 XML、MHTML 或 PDF,然后尝试从中提取数据。您应该将您关心的数据表添加到报表中,通过将其可见性更改为隐藏来隐藏该表,但将其 DataElementOutput 属性设置为输出,以便每当呈现报表时,都会包含该表。为表指定一些独特的名称(例如,将“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>

If I understand what you want to do, then yes, it is possible, but it's kind of a pain. I did this for various snapshots (as taken in Report Manager) of Report Builder 2.0 reports.

You can programmatically generate a report if you make use of your report server's built-in web services. See ReportExecutionService.Render Method for some sample code (note that I use the ReportExecution2005 web service even with SQL Server 2008). You can render the report to a variety of formats, like XML, MHTML, or PDF, and then try to extract data from that. You should add a table of the data you care about to the report, hide the table by changing its Visibility to Hide, but set its DataElementOutput property to Output so that whenever the report is rendered, the table will be included. Give the table some distinctive name (e.g., replace 'Tablix1' with 'FlatData'). You can then render the report to XML format and use XSLT to extract only the rows within that table. Here is some XSLT that I have used before to extract data from a rendered Report Builder 2.0 report:

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

Note this XSLT depends upon you naming your hidden table of data in the report to be 'FlatData'. If you know some of the data that's in your report will have HTML tags or other things that would not be valid XML if placed between two XML tags, change the XSLT above to wrap that data in CDATA tags (e.g., replace my_first_text_field with the field name whose value will need CDATA tags).

Applying this XSLT to the rendered XML version of a report will produce yet more XML, this time containing only the data from the report that you care about. The problem with just using the rendered XML version of the report is that it contains all the charts, the appearance information, etc., and isn't just your data. Try rendering one of your reports in XML format and look at the source; it has all kinds of craziness that you probably don't want.

For a command-line tool to apply XSLT transformations to XML, I recommend xalan. Here's an example usage:

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

The resulting transformed.xml will have a format like the following:

<?xml version="1.0" encoding="utf-8"?>
<ContainerElementOfMyData ReportID="MyReportName">
<MyNode>
<Key1>Value 1</Key1>
<Key2>Second value of your data</Key2>
</MyNode>
</ContainerElementOfMyData>
蓝眼睛不忧郁 2024-09-04 18:30:01

正如 Sarah Vessels 在她的回答中已经提到的,您可以推送报表服务器来渲染数据,
在许多格式中,也许 EXCEL 是不错的选择,具体取决于您的报告设计的复杂程度。
我问了类似的问题,经过多次尝试后我最终得到了Mssql 中的 #TempTaples 在报告渲染之前很疯狂,在我看来,报告服务器是作业处理的最后一个实例,所有数据和存储都应该在渲染报告的后端完成

As Sarah Vessels already mentioned in her answer You can push report server to render data,
in many formats, maybe EXCEL is not bad choice depends on complication of your report desing.
I asked similar qestion and after many trays I ended up with #TempTaples in Mssql which is madded before report is rend, looks like to me that Report Server is the last instance of job processing and all data and storage should be done in back end of rendering reports

梦醒灬来后我 2024-09-04 18:30:01

这是一个有趣的问题。当我必须解决这个问题时(用于 rdl 文件的单元测试),我编写了一个简单的 xml 解析器,它可以从 rdl 文件中提取 sql 语句并执行它。这很简单,但如果您的语句有很多参数,当然会变得更加复杂。但是,参数信息也在文件中提供,因此您应该能够编写通用解决方案(但您当然需要提供参数值)。

It's an interesting problem. When I had to solve it (for unit testing of rdl files), I wrote a simple xml parser that would extract the sql statement from the rdl file and execute it. It's quite simple, but of course get more complicated if your statements have many parameters. However the parameter info is also available in the file so you should be able to code up a generic solution (but you do of course need to supply values for the parameters).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文