如何在Jasperreports Library中调试XMLDataSource的XPath处理
JasperReports配置XPath执行日志调试XML数据源不匹配问题
问题场景
使用JasperReports Library(无服务端组件)从XML文件生成PDF报表,iReport设计完报表后执行如下代码:
JasperRunManager.runReportToPdfFile("bin/EstateAccountingMonthly.jasper", m_outputPdfFileName, parameters, xmlDataSource);
执行耗时约30秒,无异常抛出,日志输出极少,最终仅生成1页空白PDF。
已确认根因:xmlDataSource关联的XML文件Schema变更后未同步更新.JRXML报表模板,XML结构和报表内置XPath表达式完全不匹配。预期Jasper在生成过程中输出XPath执行失败的相关提示,但配置为记录所有事件的日志中无任何相关输出。
此前尝试的无效方案
曾遍历Jasper jar包,猜测可能输出相关日志的类加入日志配置(实际贴出的是Log4j2 properties格式配置),配置内容如下:
# Extra logging related to initialization of Log4j # Set to debug or trace if log4j initialization is failing status = all # Name of the configuration name = ConsoleLogConfigDemo # Console appender configuration appender.console.type = Console appender.console.name = consoleLogger appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n # Root logger level rootLogger.level = all # Root logger referring to console appender rootLogger.appenderRef.stdout.ref = consoleLogger # The following are my best guesses for which classes should be enabled for logging. logger.net_sf_jasperreports_engine_data_jrxmldatasource.name=net.sf.jasperreports.engine.data.jrxmldatasource logger.net_sf_jasperreports_engine_data_jrxmldatasource.level=ALL logger.net_sf_jasperreports_engine_data_jrxmldatasource.appenderRef.stdout.ref = consoleLogger logger.net_sf_jasperreports_data_xml_XmlDataAdapterImpl.name=net.sf_jasperreports.data.xml.XmlDataAdapterImpl logger.net_sf_jasperreports_data_xml_XmlDataAdapterImpl.level=ALL logger.net_sf_jasperreports_data_xml_XmlDataAdapterImpl.appenderRef.stdout.ref = consoleLogger logger.net_sf_jasperreports_engine_util_xml_JRXPathExecuter.name=net.sf.jasperreports.engine.util.xml.JRXPathExecuter logger.net_sf_jasperreports_engine_util_xml_JRXPathExecuter.level=ALL logger.net_sf_jasperreports_engine_util_xml_JRXPathExecuter.appenderRef.stdout.ref = consoleLogger logger.net_sf_jasperreports_engine_util_xml_XalanXPathExecuter.name=net.sf.jasperreports.engine.util.xml.XalanXPathExecuter logger.net_sf_jasperreports_engine_util_xml_XalanXPathExecuter.level=ALL logger.net_sf_jasperreports_engine_util_xml_XalanXPathExecuter.appenderRef.stdout.ref = consoleLogger logger.net_sf_jasperreports_engine_query_XalanXPathQueryExecuter.name=net.sf.jasperreports.engine.query.XalanXPathQueryExecuter logger.net_sf_jasperreports_engine_query_XalanXPathQueryExecuter.level=ALL logger.net_sf_jasperreports_engine_query_XalanXPathQueryExecuter.appenderRef.stdout.ref = consoleLogger logger.net_sf_jasperreports_engine_util_xml_JRXPathExecuterUtils.name=net.sf.jasperreports.engine.util.xml.JRXPathExecuterUtils logger.net_sf_jasperreports_engine_util_xml_JRXPathExecuterUtils.level=ALL logger.net_sf_jasperreports_engine_util_xml_JRXPathExecuterUtils.appenderRef.stdout.ref = consoleLogger logger.net_sf_jasperreports_engine_query_JRXPathQueryExecuter.name=net.sf.jasperreports.engine.query.JRXPathQueryExecuter logger.net_sf_jasperreports_engine_query_JRXPathQueryExecuter.level=ALL logger.net_sf_jasperreports_engine_query_JRXPathQueryExecuter.appenderRef.stdout.ref = consoleLogger
该配置未触发任何XPath执行相关日志输出。
配置无效的核心原因
- 类名拼写错误:多处包名分隔符错写为下划线、类名大小写错误,比如
net.sf_jasperreports.data.xml.XmlDataAdapterImpl正确应为net.sf.jasperreports.data.xml.XmlDataAdapterImpl,net.sf.jasperreports.engine.data.jrxmldatasource正确应为net.sf.jasperreports.engine.data.JRXmlDataSource,错误的类名会导致日志配置无法匹配到对应的类。 - 未开启Jasper内置的XPath调试开关:Jasper的XPath执行器默认不输出执行细节日志,必须手动开启专属debug配置才会打印表达式、返回结果等信息。
- Appender引用错误:配置里自定义的appender名称是
consoleLogger,但rootLogger和自定义logger里引用的是stdout,会导致日志无法正确输出到控制台。
正确调试步骤
1. 开启XPath执行调试开关
两种方式二选一即可:
- 全局配置方式:在项目classpath下的
jasperreports.properties中添加配置:
net.sf.jasperreports.xpath.executer.debug = true
- 代码传参方式:在传入报表的
parameters对象中添加参数,无需修改全局配置:
parameters.put("net.sf.jasperreports.xpath.executer.debug", true);
开启后Jasper会在XPath执行时打印表达式内容、上下文节点、匹配到的节点数量等信息,匹配不到节点时会明确打印返回空结果的记录。
2. 修正日志配置
以使用的Log4j2 properties格式为例,修正类名、appender引用后的配置如下,替换原有logger部分即可:
# 修正rootLogger的appender引用 rootLogger.appenderRef.console.ref = consoleLogger # JRXmlDataSource日志 logger.jrXmlDs.name=net.sf.jasperreports.engine.data.JRXmlDataSource logger.jrXmlDs.level=TRACE logger.jrXmlDs.additivity=false logger.jrXmlDs.appenderRef.console.ref=consoleLogger # XPath执行器通用日志 logger.jrXPathExec.name=net.sf.jasperreports.engine.util.xml.JRXPathExecuter logger.jrXPathExec.level=TRACE logger.jrXPathExec.additivity=false logger.jrXPathExec.appenderRef.console.ref=consoleLogger # Xalan实现类XPath执行日志 logger.xalanExec.name=net.sf.jasperreports.engine.util.xml.XalanXPathExecuter logger.xalanExec.level=TRACE logger.xalanExec.additivity=false logger.xalanExec.appenderRef.console.ref=consoleLogger # XPath查询执行器日志 logger.xPathQuery.name=net.sf.jasperreports.engine.query.JRXPathQueryExecuter logger.xPathQuery.level=TRACE logger.xPathQuery.additivity=false logger.xPathQuery.appenderRef.console.ref=consoleLogger # XML数据适配器日志 logger.xmlAdapter.name=net.sf.jasperreports.data.xml.XmlDataAdapterImpl logger.xmlAdapter.level=TRACE logger.xmlAdapter.additivity=false logger.xmlAdapter.appenderRef.console.ref=consoleLogger
3. 日志不生效的兜底方案
如果存在日志依赖冲突、配置不生效的情况,可以自定义XPath执行器包装类手动打印日志:
- 实现
JRXPathExecuter接口,包装默认的Xalan执行器,在selectNodeList、selectObject等方法执行时,手动打印传入的XPath表达式、输入节点、返回结果数。 - 实现
JRXPathExecuterFactory接口,返回上述自定义的执行器实例。 - 在全局配置或代码中设置
net.sf.jasperreports.xpath.executer.factory参数为自定义工厂类的全限定名,即可无侵入拦截所有XPath执行逻辑。
注意:JasperReports默认对XPath匹配不到节点的场景不抛出异常,仅返回空节点列表,这是无报错但输出空白页的核心原因,开启调试后即可快速定位不匹配的XPath路径。
内容的提问来源于stack exchange,提问作者mbmast
相关产品推荐
相关产品推荐

