001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * -------- 028 * CSV.java 029 * -------- 030 * (C) Copyright 2003, 2004, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * $Id: CSV.java,v 1.3.2.1 2005/10/25 21:33:38 mungady Exp $ 036 * 037 * Changes 038 * ------- 039 * 24-Nov-2003 : Version 1 (DG); 040 * 041 */ 042 043 package org.jfree.data.io; 044 045 import java.io.BufferedReader; 046 import java.io.IOException; 047 import java.io.Reader; 048 import java.util.List; 049 050 import org.jfree.data.category.CategoryDataset; 051 import org.jfree.data.category.DefaultCategoryDataset; 052 053 /** 054 * A utility class for reading {@link CategoryDataset} data from a CSV file. 055 * This initial version is very basic, and won't handle errors in the data 056 * file very gracefully. 057 */ 058 public class CSV { 059 060 /** The field delimiter. */ 061 private char fieldDelimiter; 062 063 /** The text delimiter. */ 064 private char textDelimiter; 065 066 /** 067 * Creates a new CSV reader where the field delimiter is a comma, and the 068 * text delimiter is a double-quote. 069 */ 070 public CSV() { 071 this(',', '"'); 072 } 073 074 /** 075 * Creates a new reader with the specified field and text delimiters. 076 * 077 * @param fieldDelimiter the field delimiter (usually a comma, semi-colon, 078 * colon, tab or space). 079 * @param textDelimiter the text delimiter (usually a single or double 080 * quote). 081 */ 082 public CSV(char fieldDelimiter, char textDelimiter) { 083 this.fieldDelimiter = fieldDelimiter; 084 this.textDelimiter = textDelimiter; 085 } 086 087 /** 088 * Reads a {@link CategoryDataset} from a CSV file or input source. 089 * 090 * @param in the input source. 091 * 092 * @return A category dataset. 093 * 094 * @throws IOException if there is an I/O problem. 095 */ 096 public CategoryDataset readCategoryDataset(Reader in) throws IOException { 097 098 DefaultCategoryDataset dataset = new DefaultCategoryDataset(); 099 BufferedReader reader = new BufferedReader(in); 100 List columnKeys = null; 101 int lineIndex = 0; 102 String line = reader.readLine(); 103 while (line != null) { 104 if (lineIndex == 0) { // first line contains column keys 105 columnKeys = extractColumnKeys(line); 106 } 107 else { // remaining lines contain a row key and data values 108 extractRowKeyAndData(line, dataset, columnKeys); 109 } 110 line = reader.readLine(); 111 lineIndex++; 112 } 113 return dataset; 114 115 } 116 117 /** 118 * Extracts the column keys from a string. 119 * 120 * @param line a line from the input file. 121 * 122 * @return A list of column keys. 123 */ 124 private List extractColumnKeys(String line) { 125 List keys = new java.util.ArrayList(); 126 int fieldIndex = 0; 127 int start = 0; 128 for (int i = 0; i < line.length(); i++) { 129 if (line.charAt(i) == this.fieldDelimiter) { 130 if (fieldIndex > 0) { // first field is ignored, since 131 // column 0 is for row keys 132 String key = line.substring(start, i); 133 keys.add(removeStringDelimiters(key)); 134 } 135 start = i + 1; 136 fieldIndex++; 137 } 138 } 139 String key = line.substring(start, line.length()); 140 keys.add(removeStringDelimiters(key)); 141 return keys; 142 } 143 144 /** 145 * Extracts the row key and data for a single line from the input source. 146 * 147 * @param line the line from the input source. 148 * @param dataset the dataset to be populated. 149 * @param columnKeys the column keys. 150 */ 151 private void extractRowKeyAndData(String line, 152 DefaultCategoryDataset dataset, 153 List columnKeys) { 154 Comparable rowKey = null; 155 int fieldIndex = 0; 156 int start = 0; 157 for (int i = 0; i < line.length(); i++) { 158 if (line.charAt(i) == this.fieldDelimiter) { 159 if (fieldIndex == 0) { // first field contains the row key 160 String key = line.substring(start, i); 161 rowKey = removeStringDelimiters(key); 162 } 163 else { // remaining fields contain values 164 Double value = Double.valueOf( 165 removeStringDelimiters(line.substring(start, i)) 166 ); 167 dataset.addValue( 168 value, rowKey, 169 (Comparable) columnKeys.get(fieldIndex - 1) 170 ); 171 } 172 start = i + 1; 173 fieldIndex++; 174 } 175 } 176 Double value = Double.valueOf( 177 removeStringDelimiters(line.substring(start, line.length())) 178 ); 179 dataset.addValue( 180 value, rowKey, (Comparable) columnKeys.get(fieldIndex - 1) 181 ); 182 } 183 184 /** 185 * Removes the string delimiters from a key (as well as any white space 186 * outside the delimiters). 187 * 188 * @param key the key (including delimiters). 189 * 190 * @return The key without delimiters. 191 */ 192 private String removeStringDelimiters(String key) { 193 String k = key.trim(); 194 if (k.charAt(0) == this.textDelimiter) { 195 k = k.substring(1); 196 } 197 if (k.charAt(k.length() - 1) == this.textDelimiter) { 198 k = k.substring(0, k.length() - 1); 199 } 200 return k; 201 } 202 203 }