在的Java的的开发的报表工具FineReport中,假如在目录下保存了几个XML文件,希望把XML文件转换为报表数据源,同时希望展示动态XML数据源的效果,这时可通过参数的方式,动态获取XML字段中的值再作为报表数据源。
Northwind.xml记录数据格式如下:
点击(此处)折叠或打开
-
<?xml version="1.0" encoding="UTF-8"?>
-
<Northwind>
-
<Customers>
-
<CustomerID>ALFKI</CustomerID>
-
<CompanyName>ALfreds Futterkiste</CompanyName>
-
<ContactName>Maria Anders</ContactName>
-
<ContactTitle>Sales Representative</ContactTitle>
-
<Address>Obere Str.57</Address>
-
<City>Berlin</City>
-
<PostalCode>12209</PostalCode>
-
<Country>Germany</Country>
-
<Phone>030-0074321</Phone>
-
<Fax>030-0076545</Fax>
-
</Customers>
- </Northwind>
最终用于制作报表的数据源形式如下:
?对于这样的情况我们如何来实现呢FineReport中可以通过自定义程序数据集来对XML字段数据进行解析,最终返回所希望的数据表实现步骤如下:
1,定义XMLColumnNameType4Demo封装类
首先定义参数名称及型号,供其他类直接调用,安全性比较高,详细代码如下:
点击(此处)折叠或打开
-
package com.fr.data;
-
-
public class XMLColumnNameType4Demo {
-
private int type = -1;
-
private String name = null;
-
public XMLColumnNameType4Demo(String name, int type) {
-
this.name = name;
-
this.type = type;
-
}
-
public String getName() {
-
return name;
-
}
-
public void setName(String name) {
-
this.name = name;
-
}
-
public int getType() {
-
return type;
-
}
-
public void setType(int type) {
-
this.type = type;
-
}
- }
2,定义XMLParseDemoDataModel.java类文件
定义XMLParseDemoDataModel.java类继承AbstractDataModel接口,实现getColumnCount,getColumnName,getRowCount,getValueAt四个方法,详细代码如下:
点击(此处)折叠或打开
-
package com.fr.data;
-
-
import java.io.File;
-
import java.util.ArrayList;
-
import java.util.List;
-
import javax.xml.parsers.SAXParser;
-
import javax.xml.parsers.SAXParserFactory;
-
import org.xml.sax.Attributes;
-
import org.xml.sax.SAXException;
-
import org.xml.sax.helpers.DefaultHandler;
-
import com.fr.base.FRContext;
-
import com.fr.data.AbstractDataModel;
-
import com.fr.general.ComparatorUtils;
-
import com.fr.general.data.TableDataException;
-
-
/**
-
* XMLParseDemoDataModel
-
*
-
* DataModel是获取数据的接口
-
*
-
* 这里通过init方法一次性取数后,构造一个二维表对象来实现DataModel的各个取数方法
-
*/
-
public class XMLParseDemoDataModel extends AbstractDataModel {
-
// 数据类型标识
-
public static final int COLUMN_TYPE_STRING = 0;
-
public static final int COLUMN_TYPE_INTEGER = 1;
-
public static final int COLUMN_TYPE_BOOLEAN = 2;
-
-
// 缓存取出来的数据
-
protected List row_list = null;
-
-
// 数据对应的节点路径
-
private String[] xPath;
-
// 节点路径下包含的需要取数的节点
-
private XMLColumnNameType4Demo[] columns;
-
-
private String filePath;
-
-
public XMLParseDemoDataModel(String filename, String[] xPath,
-
XMLColumnNameType4Demo[] columns) {
-
this.filePath = filename;
-
this.xPath = xPath;
-
this.columns = columns;
-
}
-
-
/**
-
* 取出列的数量
-
*/
-
public int getColumnCount() throws TableDataException {
-
return columns.length;
-
}
-
-
/**
-
* 取出相应的列的名称
-
*/
-
public String getColumnName(int columnIndex) throws TableDataException {
-
if (columnIndex < 0 || columnIndex >= columns.length)
-
return null;
-
String columnName = columns[columnIndex] == null ? null
-
: columns[columnIndex].getName();
-
-
return columnName;
-
}
-
-
/**
-
* 取出得到的结果集的总的行数
-
*/
-
public int getRowCount() throws TableDataException {
-
this.init();
-
return row_list.size();
-
}
-
-
/**
-
* 取出相应位置的值
-
*/
-
public Object getValueAt(int rowIndex, int columnIndex)
-
throws TableDataException {
-
this.init();
-
if (rowIndex < 0 || rowIndex >= row_list.size() || columnIndex < 0
-
|| columnIndex >= columns.length)
-
return null;
-
return ((Object[]) row_list.get(rowIndex))[columnIndex];
-
}
-
-
/**
-
* 释放一些资源,取数结束后,调用此方法来释放资源
-
*/
-
public void release() throws Exception {
-
if (this.row_list != null) {
-
this.row_list.clear();
-
this.row_list = null;
-
}
-
}
-
-
/** ************************************************** */
-
/** ***********以上是实现DataModel的方法*************** */
-
/** ************************************************** */
-
-
/** ************************************************** */
-
/** ************以下为解析XML文件的方法**************** */
-
/** ************************************************** */
-
-
// 一次性将数据取出来
-
protected void init() throws TableDataException {
-
if (this.row_list != null)
-
return;
-
-
this.row_list = new ArrayList();
-
try {
-
// 使用SAX解析XML文件, 使用方法请参见JAVA SAX解析
-
SAXParserFactory f = SAXParserFactory.newInstance();
-
SAXParser parser = f.newSAXParser();
-
-
parser.parse(new File(XMLParseDemoDataModel.this.filePath),
-
new DemoHandler());
-
} catch (Exception e) {
-
e.printStackTrace();
-
FRContext.getLogger().error(e.getMessage(), e);
-
}
-
}
-
-
/**
-
* 基本原理就是解析器在遍历文件时 发现节点开始标记时,调用startElement方法 读取节点内部内容时,调用characters方法
-
* 发现节点结束标记时,调用endElement
-
*/
-
private class DemoHandler extends DefaultHandler {
-
private List levelList = new ArrayList(); // 记录当前节点的路径
-
private Object[] values; // 缓存一条记录
-
private int recordIndex = -1; // 当前记录所对应的列的序号,-1表示不需要记录
-
-
public void startElement(String uri, String localName, String qName,
-
Attributes attributes) throws SAXException {
-
// 记录下
-
levelList.add(qName);
-
-
if (isRecordWrapTag()) {
-
// 开始一条新数据的记录
-
values = new Object[XMLParseDemoDataModel.this.columns.length];
-
} else if (needReadRecord()) {
-
// 看看其对应的列序号,下面的characters之后执行时,根据这个列序号来设置值存放的位置。
-
recordIndex = getColumnIndex(qName);
-
}
-
}
-
-
public void characters(char[] ch, int start, int length)
-
throws SAXException {
-
if (recordIndex > -1) {
-
// 读取值
-
String text = new String(ch, start, length);
-
XMLColumnNameType4Demo type = XMLParseDemoDataModel.this.columns[recordIndex];
-
Object value = null;
-
if (type.getType() == COLUMN_TYPE_STRING) {
-
value = text;
-
}
-
if (type.getType() == COLUMN_TYPE_INTEGER) {
-
value = new Integer(text);
-
} else if (type.getType() == COLUMN_TYPE_BOOLEAN) {
-
value = new Boolean(text);
-
}
-
-
values[recordIndex] = value;
-
}
-
}
-
-
public void endElement(String uri, String localName, String qName)
-
throws SAXException {
-
try {
-
if (isRecordWrapTag()) {
-
// 一条记录结束,就add进list中
-
XMLParseDemoDataModel.this.row_list.add(values);
-
values = null;
-
} else if (needReadRecord()) {
-
recordIndex = -1;
-
}
-
} finally {
-
levelList.remove(levelList.size() - 1);
-
}
-
}
-
-
// 正好匹配路径,确定是记录外部的Tag
-
private boolean isRecordWrapTag() {
-
if (levelList.size() == XMLParseDemoDataModel.this.xPath.length
-
&& compareXPath()) {
-
return true;
-
}
-
-
return false;
-
}
-
-
// 需要记录一条记录
-
private boolean needReadRecord() {
-
if (levelList.size() == (XMLParseDemoDataModel.this.xPath.length + 1)
-
&& compareXPath()) {
-
return true;
-
}
-
-
return false;
-
}
-
-
// 是否匹配设定的XPath路径
-
private boolean compareXPath() {
-
String[] xPath = XMLParseDemoDataModel.this.xPath;
-
for (int i = 0; i < xPath.length; i++) {
-
if (!ComparatorUtils.equals(xPath[i], levelList.get(i))) {
-
return false;
-
}
-
}
-
-
return true;
-
}
-
-
// 获取该字段的序号
-
private int getColumnIndex(String columnName) {
-
XMLColumnNameType4Demo[] nts = XMLParseDemoDataModel.this.columns;
-
for (int i = 0; i < nts.length; i++) {
-
if (ComparatorUtils.equals(nts[i].getName(), columnName)) {
-
return i;
-
}
-
}
-
-
return -1;
-
}
-
}
- }
3,定义程序数据集XMLDemoTableData
通过参数文件名,动态显示XML文件内容,首先XML文件需要放到某个目录下,如下代码是放到?盘,并且定义需要解析的数据列,这边定义的数据列名称,根XML内字段名称是一一对用的详细代码如下:
点击(此处)折叠或打开
-
return;
-
}
-
}
-
}
-
-
private void readCol0(XMLEventReader reader)
-
throws XMLStreamException {
-
while (reader.hasNext()) {
-
XMLEvent event = reader.nextEvent();
-
if (event.isStartElement()) {
-
//deep是控制层数的,只把xml中对应的层的加入到列名中
-
deep++;
-
//表示已经进入到了列名那一层
-
if(deep==COL_DEEP){
-
flag=true;
-
}
-
//如果在高层,并且已经进入到了col层,则退出
-
if(deep<COL_DEEP&&flag){
-
return;
-
}
-
if(deep!=COL_DEEP){
-
continue;
-
}
-
System.out.println("name: " + event.asStartElement().getName());
-
readCol0(reader);
-
} else if (event.isCharacters()) {
-
//对数据值不做处理
-
} else if (event.isEndElement()) {
-
deep--;
-
return;
-
}
-
}
-
}
-
public static void main(String[] args){
-
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
-
// in = new FileReader(new File(filePath));
-
// XMLEventReader reader = inputFactory.createXMLEventReader(in);
-
// readCol(reader,list);
-
BufferedInputStream in;
-
try {
-
in = new BufferedInputStream(new FileInputStream(new File("D:/tmp/f.xml")));
-
byte[] ba=new byte[3];
-
in.read(ba,0,3);
-
// System.out.println(in)
-
XMLEventReader reader = inputFactory.createXMLEventReader(in);
-
new XMLDemoTableData().readCol0(reader);
-
} catch (Exception e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
-
}
- }
注:如果XML文件的格式上问题描述处所展示的XML格式不一致,则需要修改类中的深变量,把列名所在的节点层数改成相对应的数值。
注:XMLDemoTableData里面的文件名并不是文件名,而是XML里面某个标签名。
4,编译程序数据源
分别编译XMLColumnNameType4Demo.java,XMLParseDemoDataModel.java,XMLDemoTableData.java三个类文件,将生成的类文件放于%FR_HOME%\ WebReport \ WEB-INF \类\ COM \ FR \数据下。
5配置程序数据源
新建报表,模板数据集>程序数据集,选择我们定义好的程序数据集XMLDemoTableData.class文件,名字可以自定义,如程序1。
6,使用程序数据源
在模板数据集窗口,点击预览按钮,弹出参数对话框,输入要显示的XML文件名称,点击确定则可以把Northwind.xml文件里面的数据读取出来转换报表数据源了,如下图:
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/21472864/viewspace-2126232/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/21472864/viewspace-2126232/
本文介绍如何使用FineReport工具将XML文件转换为报表数据源,包括定义数据模型、解析XML文件并实现动态展示。
610

被折叠的 条评论
为什么被折叠?



