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

本文介绍如何使用FineReport工具将XML文件转换为报表数据源,包括定义数据模型、解析XML文件并实现动态展示。

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

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


点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Northwind>
  3.     <Customers>
  4.      <CustomerID>ALFKI</CustomerID>
  5.         <CompanyName>ALfreds Futterkiste</CompanyName>
  6.         <ContactName>Maria Anders</ContactName>
  7.         <ContactTitle>Sales Representative</ContactTitle>
  8.         <Address>Obere Str.57</Address>
  9.         <City>Berlin</City>
  10.         <PostalCode>12209</PostalCode>
  11.         <Country>Germany</Country>
  12.         <Phone>030-0074321</Phone>
  13.         <Fax>030-0076545</Fax>
  14.     </Customers>
  15. </Northwind>


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


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

1,定义XMLColumnNameType4Demo封装类

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


点击(此处)折叠或打开

  1. package com.fr.data;
  2.   
  3. public class XMLColumnNameType4Demo {
  4.     private int type = -1;
  5.     private String name = null;
  6.     public XMLColumnNameType4Demo(String name, int type) {
  7.         this.name = name;
  8.         this.type = type;
  9.     }
  10.     public String getName() {
  11.         return name;
  12.     }
  13.     public void setName(String name) {
  14.         this.name = name;
  15.     }
  16.     public int getType() {
  17.         return type;
  18.     }
  19.     public void setType(int type) {
  20.         this.type = type;
  21.     }
  22. }


2,定义XMLParseDemoDataModel.java类文件

定义XMLParseDemoDataModel.java类继承AbstractDataModel接口,实现getColumnCount,getColumnName,getRowCount,getValueAt四个方法,详细代码如下:


点击(此处)折叠或打开

  1. package com.fr.data;
  2.   
  3. import java.io.File;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import javax.xml.parsers.SAXParser;
  7. import javax.xml.parsers.SAXParserFactory;
  8. import org.xml.sax.Attributes;
  9. import org.xml.sax.SAXException;
  10. import org.xml.sax.helpers.DefaultHandler;
  11. import com.fr.base.FRContext;
  12. import com.fr.data.AbstractDataModel;
  13. import com.fr.general.ComparatorUtils;
  14. import com.fr.general.data.TableDataException;
  15.   
  16. /**
  17.  * XMLParseDemoDataModel
  18.  *
  19.  * DataModel是获取数据的接口
  20.  *
  21.  * 这里通过init方法一次性取数后,构造一个二维表对象来实现DataModel的各个取数方法
  22.  */
  23. public class XMLParseDemoDataModel extends AbstractDataModel {
  24.     // 数据类型标识
  25.     public static final int COLUMN_TYPE_STRING = 0;
  26.     public static final int COLUMN_TYPE_INTEGER = 1;
  27.     public static final int COLUMN_TYPE_BOOLEAN = 2;
  28.   
  29.     // 缓存取出来的数据
  30.     protected List row_list = null;
  31.   
  32.     // 数据对应的节点路径
  33.     private String[] xPath;
  34.     // 节点路径下包含的需要取数的节点
  35.     private XMLColumnNameType4Demo[] columns;
  36.   
  37.     private String filePath;
  38.   
  39.     public XMLParseDemoDataModel(String filename, String[] xPath,
  40.             XMLColumnNameType4Demo[] columns) {
  41.         this.filePath = filename;
  42.         this.xPath = xPath;
  43.         this.columns = columns;
  44.     }
  45.   
  46.     /**
  47.      * 取出列的数量
  48.      */
  49.     public int getColumnCount() throws TableDataException {
  50.         return columns.length;
  51.     }
  52.   
  53.     /**
  54.      * 取出相应的列的名称
  55.      */
  56.     public String getColumnName(int columnIndex) throws TableDataException {
  57.         if (columnIndex < 0 || columnIndex >= columns.length)
  58.             return null;
  59.         String columnName = columns[columnIndex] == null ? null
  60.                 : columns[columnIndex].getName();
  61.   
  62.         return columnName;
  63.     }
  64.   
  65.     /**
  66.      * 取出得到的结果集的总的行数
  67.      */
  68.     public int getRowCount() throws TableDataException {
  69.         this.init();
  70.         return row_list.size();
  71.     }
  72.   
  73.     /**
  74.      * 取出相应位置的值
  75.      */
  76.     public Object getValueAt(int rowIndex, int columnIndex)
  77.             throws TableDataException {
  78.         this.init();
  79.         if (rowIndex < 0 || rowIndex >= row_list.size() || columnIndex < 0
  80.                 || columnIndex >= columns.length)
  81.             return null;
  82.         return ((Object[]) row_list.get(rowIndex))[columnIndex];
  83.     }
  84.   
  85.     /**
  86.      * 释放一些资源,取数结束后,调用此方法来释放资源
  87.      */
  88.     public void release() throws Exception {
  89.         if (this.row_list != null) {
  90.             this.row_list.clear();
  91.             this.row_list = null;
  92.         }
  93.     }
  94.   
  95.     /** ************************************************** */
  96.     /** ***********以上是实现DataModel的方法*************** */
  97.     /** ************************************************** */
  98.   
  99.     /** ************************************************** */
  100.     /** ************以下为解析XML文件的方法**************** */
  101.     /** ************************************************** */
  102.   
  103.     // 一次性将数据取出来
  104.     protected void init() throws TableDataException {
  105.         if (this.row_list != null)
  106.             return;
  107.   
  108.         this.row_list = new ArrayList();
  109.         try {
  110.             // 使用SAX解析XML文件, 使用方法请参见JAVA SAX解析
  111.             SAXParserFactory f = SAXParserFactory.newInstance();
  112.             SAXParser parser = f.newSAXParser();
  113.   
  114.             parser.parse(new File(XMLParseDemoDataModel.this.filePath),
  115.                     new DemoHandler());
  116.         } catch (Exception e) {
  117.             e.printStackTrace();
  118.             FRContext.getLogger().error(e.getMessage(), e);
  119.         }
  120.     }
  121.   
  122.     /**
  123.      * 基本原理就是解析器在遍历文件时 发现节点开始标记时,调用startElement方法 读取节点内部内容时,调用characters方法
  124.      * 发现节点结束标记时,调用endElement
  125.      */
  126.     private class DemoHandler extends DefaultHandler {
  127.         private List levelList = new ArrayList(); // 记录当前节点的路径
  128.         private Object[] values; // 缓存一条记录
  129.         private int recordIndex = -1; // 当前记录所对应的列的序号,-1表示不需要记录
  130.   
  131.         public void startElement(String uri, String localName, String qName,
  132.                 Attributes attributes) throws SAXException {
  133.             // 记录下
  134.             levelList.add(qName);
  135.   
  136.             if (isRecordWrapTag()) {
  137.                 // 开始一条新数据的记录
  138.                 values = new Object[XMLParseDemoDataModel.this.columns.length];
  139.             } else if (needReadRecord()) {
  140.                 // 看看其对应的列序号,下面的characters之后执行时,根据这个列序号来设置值存放的位置。
  141.                 recordIndex = getColumnIndex(qName);
  142.             }
  143.         }
  144.   
  145.         public void characters(char[] ch, int start, int length)
  146.                 throws SAXException {
  147.             if (recordIndex > -1) {
  148.                 // 读取值
  149.                 String text = new String(ch, start, length);
  150.                 XMLColumnNameType4Demo type = XMLParseDemoDataModel.this.columns[recordIndex];
  151.                 Object value = null;
  152.                 if (type.getType() == COLUMN_TYPE_STRING) {
  153.                     value = text;
  154.                 }
  155.                 if (type.getType() == COLUMN_TYPE_INTEGER) {
  156.                     value = new Integer(text);
  157.                 } else if (type.getType() == COLUMN_TYPE_BOOLEAN) {
  158.                     value = new Boolean(text);
  159.                 }
  160.   
  161.                 values[recordIndex] = value;
  162.             }
  163.         }
  164.   
  165.         public void endElement(String uri, String localName, String qName)
  166.                 throws SAXException {
  167.             try {
  168.                 if (isRecordWrapTag()) {
  169.                     // 一条记录结束,就add进list中
  170.                     XMLParseDemoDataModel.this.row_list.add(values);
  171.                     values = null;
  172.                 } else if (needReadRecord()) {
  173.                     recordIndex = -1;
  174.                 }
  175.             } finally {
  176.                 levelList.remove(levelList.size() - 1);
  177.             }
  178.         }
  179.   
  180.         // 正好匹配路径,确定是记录外部的Tag
  181.         private boolean isRecordWrapTag() {
  182.             if (levelList.size() == XMLParseDemoDataModel.this.xPath.length
  183.                     && compareXPath()) {
  184.                 return true;
  185.             }
  186.   
  187.             return false;
  188.         }
  189.   
  190.         // 需要记录一条记录
  191.         private boolean needReadRecord() {
  192.             if (levelList.size() == (XMLParseDemoDataModel.this.xPath.length + 1)
  193.                     && compareXPath()) {
  194.                 return true;
  195.             }
  196.   
  197.             return false;
  198.         }
  199.   
  200.         // 是否匹配设定的XPath路径
  201.         private boolean compareXPath() {
  202.             String[] xPath = XMLParseDemoDataModel.this.xPath;
  203.             for (int i = 0; i < xPath.length; i++) {
  204.                 if (!ComparatorUtils.equals(xPath[i], levelList.get(i))) {
  205.                     return false;
  206.                 }
  207.             }
  208.   
  209.             return true;
  210.         }
  211.   
  212.         // 获取该字段的序号
  213.         private int getColumnIndex(String columnName) {
  214.             XMLColumnNameType4Demo[] nts = XMLParseDemoDataModel.this.columns;
  215.             for (int i = 0; i < nts.length; i++) {
  216.                 if (ComparatorUtils.equals(nts[i].getName(), columnName)) {
  217.                     return i;
  218.                 }
  219.             }
  220.   
  221.             return -1;
  222.         }
  223.     }
  224. }


3,定义程序数据集XMLDemoTableData

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

点击(此处)折叠或打开

  1. return;
  2.             }
  3.         }
  4.     }
  5.       
  6.     private void readCol0(XMLEventReader reader)
  7.             throws XMLStreamException {
  8.         while (reader.hasNext()) {
  9.             XMLEvent event = reader.nextEvent();
  10.             if (event.isStartElement()) {
  11.                 //deep是控制层数的,只把xml中对应的层的加入到列名中
  12.                 deep++;
  13.                 //表示已经进入到了列名那一层
  14.                 if(deep==COL_DEEP){
  15.                     flag=true;
  16.                 }
  17.                 //如果在高层,并且已经进入到了col层,则退出
  18.                 if(deep<COL_DEEP&&flag){
  19.                     return;
  20.                 }
  21.                 if(deep!=COL_DEEP){
  22.                     continue;
  23.                 }
  24.                 System.out.println("name: " + event.asStartElement().getName());
  25.                 readCol0(reader);
  26.             } else if (event.isCharacters()) {
  27.                 //对数据值不做处理
  28.             } else if (event.isEndElement()) {
  29.                 deep--;
  30.                 return;
  31.             }
  32.         }
  33.     }
  34.     public static void main(String[] args){
  35.         XMLInputFactory inputFactory = XMLInputFactory.newInstance();
  36. // in = new FileReader(new File(filePath));
  37. // XMLEventReader reader = inputFactory.createXMLEventReader(in);
  38. // readCol(reader,list);
  39.         BufferedInputStream in;
  40.         try {
  41.             in = new BufferedInputStream(new FileInputStream(new File("D:/tmp/f.xml")));
  42.             byte[] ba=new byte[3];
  43.             in.read(ba,0,3);
  44. // System.out.println(in)
  45.         XMLEventReader reader = inputFactory.createXMLEventReader(in);
  46.         new XMLDemoTableData().readCol0(reader);
  47.         } catch (Exception e) {
  48.                 // TODO Auto-generated catch block
  49.                 e.printStackTrace();
  50.             }
  51.     }
  52. }


注:如果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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值