Source for org.jfree.data.io.CSV

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * --------
  28:  * CSV.java
  29:  * --------
  30:  * (C) Copyright 2003-2007, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * Changes
  36:  * -------
  37:  * 24-Nov-2003 : Version 1 (DG);
  38:  *
  39:  */
  40: 
  41: package org.jfree.data.io;
  42: 
  43: import java.io.BufferedReader;
  44: import java.io.IOException;
  45: import java.io.Reader;
  46: import java.util.List;
  47: 
  48: import org.jfree.data.category.CategoryDataset;
  49: import org.jfree.data.category.DefaultCategoryDataset;
  50: 
  51: /**
  52:  * A utility class for reading {@link CategoryDataset} data from a CSV file.  
  53:  * This initial version is very basic, and won't handle errors in the data 
  54:  * file very gracefully.
  55:  */
  56: public class CSV {
  57: 
  58:     /** The field delimiter. */
  59:     private char fieldDelimiter;
  60:     
  61:     /** The text delimiter. */
  62:     private char textDelimiter;
  63:      
  64:     /** 
  65:      * Creates a new CSV reader where the field delimiter is a comma, and the 
  66:      * text delimiter is a double-quote.
  67:      */
  68:     public CSV() {
  69:         this(',', '"');    
  70:     }
  71:     
  72:     /**
  73:      * Creates a new reader with the specified field and text delimiters.
  74:      * 
  75:      * @param fieldDelimiter  the field delimiter (usually a comma, semi-colon,
  76:      *                        colon, tab or space).
  77:      * @param textDelimiter  the text delimiter (usually a single or double 
  78:      *                       quote).
  79:      */
  80:     public CSV(char fieldDelimiter, char textDelimiter) {
  81:         this.fieldDelimiter = fieldDelimiter;
  82:         this.textDelimiter = textDelimiter;
  83:     }
  84:     
  85:     /**
  86:      * Reads a {@link CategoryDataset} from a CSV file or input source.
  87:      * 
  88:      * @param in  the input source.
  89:      * 
  90:      * @return A category dataset.
  91:      * 
  92:      * @throws IOException if there is an I/O problem.
  93:      */
  94:     public CategoryDataset readCategoryDataset(Reader in) throws IOException {
  95:         
  96:         DefaultCategoryDataset dataset = new DefaultCategoryDataset();
  97:         BufferedReader reader = new BufferedReader(in);
  98:         List columnKeys = null;
  99:         int lineIndex = 0;
 100:         String line = reader.readLine();
 101:         while (line != null) {
 102:             if (lineIndex == 0) {  // first line contains column keys
 103:                 columnKeys = extractColumnKeys(line);
 104:             }
 105:             else {  // remaining lines contain a row key and data values
 106:                 extractRowKeyAndData(line, dataset, columnKeys);
 107:             }
 108:             line = reader.readLine();
 109:             lineIndex++;
 110:         }
 111:         return dataset;     
 112:          
 113:     }
 114:     
 115:     /**
 116:      * Extracts the column keys from a string.
 117:      * 
 118:      * @param line  a line from the input file.
 119:      * 
 120:      * @return A list of column keys.
 121:      */
 122:     private List extractColumnKeys(String line) {
 123:         List keys = new java.util.ArrayList();
 124:         int fieldIndex = 0;
 125:         int start = 0;
 126:         for (int i = 0; i < line.length(); i++) {
 127:             if (line.charAt(i) == this.fieldDelimiter) {
 128:                 if (fieldIndex > 0) {  // first field is ignored, since 
 129:                                        // column 0 is for row keys
 130:                     String key = line.substring(start, i);
 131:                     keys.add(removeStringDelimiters(key));
 132:                 }
 133:                 start = i + 1;
 134:                 fieldIndex++;
 135:             }
 136:         }
 137:         String key = line.substring(start, line.length());
 138:         keys.add(removeStringDelimiters(key));
 139:         return keys;        
 140:     }
 141:     
 142:     /**
 143:      * Extracts the row key and data for a single line from the input source.
 144:      * 
 145:      * @param line  the line from the input source.
 146:      * @param dataset  the dataset to be populated.
 147:      * @param columnKeys  the column keys.
 148:      */
 149:     private void extractRowKeyAndData(String line,
 150:                                       DefaultCategoryDataset dataset,
 151:                                       List columnKeys) {
 152:         Comparable rowKey = null;
 153:         int fieldIndex = 0;
 154:         int start = 0;
 155:         for (int i = 0; i < line.length(); i++) {
 156:             if (line.charAt(i) == this.fieldDelimiter) {
 157:                 if (fieldIndex == 0) {  // first field contains the row key
 158:                     String key = line.substring(start, i);
 159:                     rowKey = removeStringDelimiters(key);
 160:                 }
 161:                 else {  // remaining fields contain values
 162:                     Double value = Double.valueOf(
 163:                         removeStringDelimiters(line.substring(start, i))
 164:                     );
 165:                     dataset.addValue(
 166:                         value, rowKey, 
 167:                         (Comparable) columnKeys.get(fieldIndex - 1)
 168:                     );
 169:                 }
 170:                 start = i + 1;
 171:                 fieldIndex++;
 172:             }
 173:         }
 174:         Double value = Double.valueOf(
 175:             removeStringDelimiters(line.substring(start, line.length()))
 176:         );
 177:         dataset.addValue(
 178:             value, rowKey, (Comparable) columnKeys.get(fieldIndex - 1)
 179:         ); 
 180:     }
 181:     
 182:     /**
 183:      * Removes the string delimiters from a key (as well as any white space 
 184:      * outside the delimiters).
 185:      * 
 186:      * @param key  the key (including delimiters).
 187:      * 
 188:      * @return The key without delimiters.
 189:      */
 190:     private String removeStringDelimiters(String key) {
 191:         String k = key.trim();
 192:         if (k.charAt(0) == this.textDelimiter) {
 193:             k = k.substring(1);
 194:         }
 195:         if (k.charAt(k.length() - 1) == this.textDelimiter) {
 196:             k = k.substring(0, k.length() - 1);
 197:         }
 198:         return k;
 199:     }
 200:     
 201: }