2

我想要共享(模板)适用于各种 XML 数据源的 .JRXML 文件。

我所知道的唯一可能会阻止这种情况的是,现场规格会略有不同。

对于一个 XML 文件,名称字段的 XPATH 可能是:

   person/name/last

对于另一个 XML 文件,XPATH 可能是:

   contact/last_name

理想情况下,我可以将 XPATH 作为参数传递并像这样使用它:

 <field name="name" class="java.lang.String">
    <fieldDescription> $P{NAME_XPATH} </fieldDescription>
</field>

但是 Jasper 似乎不支持在<fieldDescription>标签中使用参数。

我是否可以通过某种方式将字段规范注入到我的 JRXML 模板中?

4

2 回答 2

0

由于您的系统是基于 XML 的,为什么不使用 XSLT?您的 JRXML 模板可以调整为 XSL 样式表,然后使用您的 XML 配置文件作为输入,XSLT 处理器可以将字段描述替换为配置内容。

示例: JRXML/XSL

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/report-config">

    <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd">

    ...

    <field name="name" class="java.lang.String">
        <fieldDescription><xsl:value-of select="name"/></fieldDescription>
    </field>

    ...

    </jasperReport>

  </xsl:template>
</xsl:stylesheet>

配置 XML

<?xml version="1.0" encoding="ISO-8859-1"?>
<report-config>
    <name>person/name/last</name>
</report-config>
于 2013-03-28T15:09:33.067 回答
0

Jasper 不支持在<fieldDescription>标签中使用参数。

我下载了 Jasper 源代码,但我认为您无法通过简单地实现替代方法来添加此功能XPathExecutor。原因是因为包含参数的上下文对 XPathExecutor 工厂类不可用。简而言之,需要添加很多上下文传递。

您当然可以尝试添加它,但它会影响许多类文件,然后它会成为 Jasper 可能无法接受的那种更改,并且您将永远合并不同的源。

我不准备冒这个险。另外,我认为 Jasper 迟早会添加这个。

但是,我确实提出了一个解决方案,该解决方案基本上涉及编写您自己的自定义 XPathExecutor,然后通过 Threadlocal 变量实现将上下文传递给它。在下面的示例代码中,Threadlocal 变量是ReportGeneratorJasper.requestContext

static ThreadLocal<ReportRequest> requestContext;    

这是在我的班级中设置自定义 XPathExecutor 的代码ReportGeneratorJasper

    JasperReport repResource = getJasperReport(report);
    JasperPrint jp = null;

    // Setup for eReports XPATH executers
    //
    JasperReportsContext jrc = DefaultJasperReportsContext.getInstance();
    jrc.setProperty(
        JRXPathExecuterUtils.PROPERTY_XPATH_EXECUTER_FACTORY, 
        XalanNamedParameterXPathExecutor.class.getCanonicalName());

    requestContext = 
               new ThreadLocal<ReportRequest>() {
                         protected synchronized ReportRequest initialValue() {
                         return request;
             };
    };

    JasperFillManager jfm = JasperFillManager.getInstance(jrc);

ReportRequest 是我自己的 bean,它包含定义“这个”特定报告生成请求的所有属性。

这是自定义的 XPathExecutor(它也提供了自己的工厂)。:

public class XalanNamedParameterXPathExecutor 
            extends XalanXPathExecuter implements JRXPathExecuterFactory {

    // Reference to the Threadlocal
    //
    private ReportRequest request;

    public static final String PREFIX = "$";

    public XalanNamedParameterXPathExecutor() {
        this.request = ReportGeneratorJasper.requestContext.get();
    }

    @Override
    public Object selectObject(Node arg0, String xpath) throws JRException {

        String useXpath = xpath;

        if (xpath.startsWith("$")) {
            String value = request.getScalarParamAsString(xpath);
            useXpath = (value != null ? value : xpath);         
        }

        return super.selectObject(arg0, useXpath);
    }

    @Override
    public JRXPathExecuter getXPathExecuter() {
        return new XalanNamedParameterXPathExecutor();
    }

使用 Threadlocal 并不是一个理想的解决方案。如果报表填充器在不同的线程中运行,它很容易中断。但在当前版本的 Jasper 中,这似乎不是问题。

希望 Jasper 将为此实现内置支持。

于 2013-04-02T18:59:19.973 回答