打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Java如何解析某个目录下xml文件,将其转换为报表数据源?

在Java开发的报表工具FineReport中,假如在目录下保存了几个XML文件,希望把XML文件转换为报表数据源,同时希望展示动态xml数据源的效果,这时可通过参数的方式,动态获取xml字段中的值再作为报表数据源。

Northwind.xml记录数据格式如下:

ALFKI ALfreds Futterkiste Maria Anders Sales Representative

Obere Str.57
Berlin 12209 Germany 030-0074321 030-0076545

最终用于制作报表的数据源形式如下:

对于这样的情况我们如何来实现呢?FineReport中可以通过自定义程序数据集来对xml字段数据进行解析,最终返回所希望的数据表。实现步骤如下:

1、 定义XMLColumnNameType4Demo封装类

首先定义参数name及type,供其他类直接调用,安全性比较高,详细代码如下:

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

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

通过参数filename,动态显示xml文件内容,首先xml文件需要放到某个目录下,如下代码是放到D盘,并且定义需要解析的数据列,这边定义的数据列名称,根xml内字段名称是一一对用的。详细代码如下:

packagecom.fr.data;

importjava.io.BufferedInputStream;

importjava.io.ByteArrayInputStream;

importjava.io.File;

importjava.io.FileInputStream;

importjava.io.FileNotFoundException;

importjava.io.FileReader;

importjava.io.InputStream;

importjava.io.Reader;

importjava.util.*;

importjavax.xml.stream.XMLEventReader;

importjavax.xml.stream.XMLInputFactory;

importjavax.xml.stream.XMLStreamException;

importjavax.xml.stream.events.XMLEvent;

importcom.fr.base.Parameter;

importcom.fr.data.AbstractParameterTableData;

importcom.fr.general.data.DataModel;

importcom.fr.script.Calculator;

importcom.fr.stable.ParameterProvider;

importcom.fr.stable.StringUtils;

/**

* XMLDemoTableData

*

* 这是一个按参数来解析不同地址XML文件的demo

*

* AbstractParameterTableData 包装了有参数数据集的基本实现

*/ publicclass XMLDemoTableData extends AbstractParameterTableData {

// 构造函数

public XMLDemoTableData() {

// 定义需要的参数,这里定义一个参数,参数名为filename,给其一个默认值'Northwind.xml'

this.parameters = newParameter[1];

this.parameters[0] = newParameter('filename', 'Northwind');

}

/**

* 返回获取数据的执行对象

* 系统取数时,调用此方法来返回一个获取数据的执行对象

* 注意!当数据集需要根据不同参数来多次取数时,此方法在一个计算过程中会被多次调用。

*/

@SuppressWarnings('unchecked')

public DataModel createDataModel(Calculatorcalculator) {

// 获取传进来的参数

ParameterProvider[] params =super.processParameters(calculator);

// 根据传进来的参数,等到文件的路径

String filename = null;

for (int i = 0; i < params.length;i++)="">

if (params[i] == null)continue;

if('filename'.equals(params[i].getName())) {

filename =(String)params[i].getValue();

}

}

String filePath;

if (StringUtils.isBlank(filename)){

filePath ='D://DefaultFile.xml';

} else {

filePath = 'D://' +filename + '.xml';

}

// 定义需要解析的数据列,机器 // XMLColumnNameType4Demo[] columns = newXMLColumnNameType4Demo[7]; // columns[0] = newXMLColumnNameType4Demo('CustomerID',XMLParseDemoDataModel.COLUMN_TYPE_STRING); // columns[1] = newXMLColumnNameType4Demo('CompanyName',XMLParseDemoDataModel.COLUMN_TYPE_STRING); // columns[2] = newXMLColumnNameType4Demo('ContactName',XMLParseDemoDataModel.COLUMN_TYPE_STRING); // columns[3] = newXMLColumnNameType4Demo('ContactTitle',XMLParseDemoDataModel.COLUMN_TYPE_STRING); // columns[4] = newXMLColumnNameType4Demo('Address',XMLParseDemoDataModel.COLUMN_TYPE_STRING); // columns[5] = newXMLColumnNameType4Demo('City',XMLParseDemoDataModel.COLUMN_TYPE_STRING); // columns[6] = new XMLColumnNameType4Demo('Phone',XMLParseDemoDataModel.COLUMN_TYPE_STRING);

List list=new ArrayList();

XMLInputFactory inputFactory =XMLInputFactory.newInstance();

InputStream in;

try {

in = new BufferedInputStream(newFileInputStream(new File(filePath)));

XMLEventReader reader =inputFactory.createXMLEventReader(in);

readCol(reader,list);

in.close();

} catch (Exception e) {

// TODO Auto-generated catchblock

e.printStackTrace();

}

XMLColumnNameType4Demo[]columns=(XMLColumnNameType4Demo[])list.toArray(newXMLColumnNameType4Demo[0]);

// 定义解析的数据在xml文件结构中的位置

String[] xpath = new String[2];

xpath[0] = 'Northwind';

xpath[1] = 'Customers';

/*

* 说明

* 提供的样例xml文件的格式是:

*

*

* ALFKI

* AlfredsFutterkiste

* MariaAnders

* SalesRepresentative

*

Obere Str. 57

* Berlin

* 12209

* Germany

* 030-0074321

* 030-0076545

*

*

*

* 上面定义的意义就是

* /Northwind/Customers路径所表示的一个Customers节点为一条数据,它包含的节点中的CustomerID...等等是需要获取的列值

*/

// 构造一个实际去取值的执行对象

return new XMLParseDemoDataModel(filePath,xpath, columns);

}

private int deep=0;

private static final int COL_DEEP=3;

private boolean flag=false;

private void readCol(XMLEventReader reader,List list)

throws XMLStreamException {

while (reader.hasNext()) {

XMLEvent event =reader.nextEvent();

if (event.isStartElement()) {

//deep是控制层数的,只把xml中对应的层的加入到列名中

deep++;

//表示已经进入到了列名那一层

if(deep==COL_DEEP){

flag=true;

}

//如果在高层,并且已经进入到了col层,则退出

if(deep<>

return;

}

if(deep!=COL_DEEP){

continue;

}

// println('name: ' +event.asStartElement().getName());

XMLColumnNameType4Democolumn=new XMLColumnNameType4Demo(event.asStartElement().getName().toString(),XMLParseDemoDataModel.COLUMN_TYPE_STRING);

list.add(column);

readCol(reader,list);

} else if (event.isCharacters()){

//对数据值不做处理

} else if (event.isEndElement()){

deep--;

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

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(newFile(filePath)); // XMLEventReader reader = inputFactory.createXMLEventReader(in); // readCol(reader,list);

BufferedInputStream in;

try {

in = new BufferedInputStream(newFileInputStream(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);

newXMLDemoTableData().readCol0(reader);

} catch (Exception e) {

// TODO Auto-generated catchblock

e.printStackTrace();

}

}

}

注:如果xml文件的格式上问题描述处所展示的xml格式不一致,则需要修改类中的deep变量,把列名所在的节点层数改成相对应的数值。

注:XMLDemoTableData里面的filename并不是文件名,而是xml里面某个标签名。

4、编译程序数据源

分别编译XMLColumnNameType4Demo.java、XMLParseDemoDataModel.java、XMLDemoTableData.java三个类文件,将生成的class文件放于%FR_HOME%\WebReport\WEB-INF\classes\com\fr\data下。

5 配置程序数据源

新建报表,模板数据集>程序数据集,选择我们定义好的程序数据集XMLDemoTableData.class文件,名字可以自定义,如程序1。

6、使用程序数据源

在模板数据集窗口,点击预览按钮,弹出参数对话框,输入要显示的xml文件名称,点击确定则可以把Northwind.xml文件里面的数据读取出来转换报表数据源了,如下图:

习Java的同学注意了!!!

学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:184625948【长按复制】 我们一起学Java!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
用DOM/JDOM解析XML文件(3)
C# XML解析方式实例解析
VC知识库文章
C#中对 XML节点进行增、删、改、查
Java 使用poi导入excel,结合xml文件进行数据验证的例子(增加了jar包)
hibernate创建xml映射和创建数据表
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服