Java軟件報表軟件技術博客

          java報表軟件技術匯總 java報表軟件制作 報表軟件新聞
          posts - 355, comments - 100, trackbacks - 0, articles - 3
             :: 首頁 :: 新隨筆 ::  :: 聚合  :: 管理

          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封裝類

          首先定義參數nametype,供其他類直接調用,安全性比較高,詳細代碼如下:


          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接口,實現getColumnCountgetColumnNamegetRowCountgetValueAt四個方法,詳細代碼如下:


          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

          通過參數filename,動態顯示xml文件內容,首先xml文件需要放到某個目錄下,如下代碼是放到D盤,并且定義需要解析的數據列,這邊定義的數據列名稱,根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();  
                      }  
              }  
          }

           

          5 配置程序數據源

          新建報表,模板數據集>程序數據集,選擇我們定義好的程序數據集XMLDemoTableData.class文件,名字可以自定義,如程序1


          6、使用程序數據源

          在模板數據集窗口,點擊預覽按鈕,彈出參數對話框,輸入要顯示的xml文件名稱,點擊確定則可以把Northwind.xml文件里面的數據讀取出來轉換報表數據源了,如下圖:




          主站蜘蛛池模板: 钦州市| 乐平市| 永清县| 临湘市| 黄陵县| 三都| 大同县| 龙南县| 东莞市| 东乌珠穆沁旗| 平凉市| 武平县| 青神县| 昭通市| 土默特左旗| 运城市| 武宣县| 加查县| 平乡县| 石景山区| 满城县| 禄劝| 南投市| 屏东市| 靖西县| 沁阳市| 福安市| 囊谦县| 原阳县| 柳林县| 太白县| 宿迁市| 定边县| 嘉荫县| 巴南区| 精河县| 盐山县| 南陵县| 宜黄县| 仁寿县| 湟中县|