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 }