001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, 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-2007, by Object Refinery Limited.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): -;
034 *
035 * Changes
036 * -------
037 * 24-Nov-2003 : Version 1 (DG);
038 *
039 */
040
041 package org.jfree.data.io;
042
043 import java.io.BufferedReader;
044 import java.io.IOException;
045 import java.io.Reader;
046 import java.util.List;
047
048 import org.jfree.data.category.CategoryDataset;
049 import org.jfree.data.category.DefaultCategoryDataset;
050
051 /**
052 * A utility class for reading {@link CategoryDataset} data from a CSV file.
053 * This initial version is very basic, and won't handle errors in the data
054 * file very gracefully.
055 */
056 public class CSV {
057
058 /** The field delimiter. */
059 private char fieldDelimiter;
060
061 /** The text delimiter. */
062 private char textDelimiter;
063
064 /**
065 * Creates a new CSV reader where the field delimiter is a comma, and the
066 * text delimiter is a double-quote.
067 */
068 public CSV() {
069 this(',', '"');
070 }
071
072 /**
073 * Creates a new reader with the specified field and text delimiters.
074 *
075 * @param fieldDelimiter the field delimiter (usually a comma, semi-colon,
076 * colon, tab or space).
077 * @param textDelimiter the text delimiter (usually a single or double
078 * quote).
079 */
080 public CSV(char fieldDelimiter, char textDelimiter) {
081 this.fieldDelimiter = fieldDelimiter;
082 this.textDelimiter = textDelimiter;
083 }
084
085 /**
086 * Reads a {@link CategoryDataset} from a CSV file or input source.
087 *
088 * @param in the input source.
089 *
090 * @return A category dataset.
091 *
092 * @throws IOException if there is an I/O problem.
093 */
094 public CategoryDataset readCategoryDataset(Reader in) throws IOException {
095
096 DefaultCategoryDataset dataset = new DefaultCategoryDataset();
097 BufferedReader reader = new BufferedReader(in);
098 List columnKeys = null;
099 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 }