将Jasper参数注入字段规范

时间:2013-03-27 15:16:43

标签: jasper-reports

我想拥有适用于各种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模板吗?

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分:0)

Jasper不支持在<fieldDescription>代码中使用参数。

我下载了Jasper资源,我认为您只需实施替代XPathExecutor即可添加此功能。原因是因为包含参数的上下文不可用于XPathExecutor工厂类。简而言之,需要添加大量的上下文传递。

你当然可以尝试添加它,但它会影响许多类文件,然后它变成Jasper可能无法接收的那种变化,并且你将永远合并你的不同来源。

我还没准备冒这个风险。另外,我认为贾斯珀迟早会加上这个。

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

static ThreadLocal<ReportRequest> requestContext;    

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

    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,它包含定义&#34;这个&#34;的所有属性。特定的报告生成请求。

这是自定义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能为此实现内置支持。