1. /* ===========================================================
  2. * JFreeChart : a free chart library for the Java(tm) platform
  3. * ===========================================================
  4. *
  5. * (C) Copyright 2000-2005, 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 License
  20. * along with this library; if not, write to the Free Software Foundation,
  21. * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  22. *
  23. * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  24. * in the United States and other countries.]
  25. *
  26. * --------
  27. * CSV.java
  28. * --------
  29. * (C) Copyright 2003, 2004, by Object Refinery Limited.
  30. *
  31. * Original Author: David Gilbert (for Object Refinery Limited);
  32. * Contributor(s): -;
  33. *
  34. * $Id: CSV.java,v 1.3 2005/02/24 10:44:56 mungady Exp $
  35. *
  36. * Changes
  37. * -------
  38. * 24-Nov-2003 : Version 1 (DG);
  39. *
  40. */
  41. package org.jfree.data.io;
  42. import java.io.BufferedReader;
  43. import java.io.IOException;
  44. import java.io.Reader;
  45. import java.util.List;
  46. import org.jfree.data.category.CategoryDataset;
  47. import org.jfree.data.category.DefaultCategoryDataset;
  48. /**
  49. * A utility class for reading {@link CategoryDataset} data from a CSV file.
  50. * This initial version is very basic, and won't handle errors in the data
  51. * file very gracefully.
  52. */
  53. public class CSV {
  54. /** The field delimiter. */
  55. private char fieldDelimiter;
  56. /** The text delimiter. */
  57. private char textDelimiter;
  58. /**
  59. * Creates a new CSV reader where the field delimiter is a comma, and the
  60. * text delimiter is a double-quote.
  61. */
  62. public CSV() {
  63. this(',', '"');
  64. }
  65. /**
  66. * Creates a new reader with the specified field and text delimiters.
  67. *
  68. * @param fieldDelimiter the field delimiter (usually a comma, semi-colon,
  69. * colon, tab or space).
  70. * @param textDelimiter the text delimiter (usually a single or double
  71. * quote).
  72. */
  73. public CSV(char fieldDelimiter, char textDelimiter) {
  74. this.fieldDelimiter = fieldDelimiter;
  75. this.textDelimiter = textDelimiter;
  76. }
  77. /**
  78. * Reads a {@link CategoryDataset} from a CSV file or input source.
  79. *
  80. * @param in the input source.
  81. *
  82. * @return A category dataset.
  83. *
  84. * @throws IOException if there is an I/O problem.
  85. */
  86. public CategoryDataset readCategoryDataset(Reader in) throws IOException {
  87. DefaultCategoryDataset dataset = new DefaultCategoryDataset();
  88. BufferedReader reader = new BufferedReader(in);
  89. List columnKeys = null;
  90. int lineIndex = 0;
  91. String line = reader.readLine();
  92. while (line != null) {
  93. if (lineIndex == 0) { // first line contains column keys
  94. columnKeys = extractColumnKeys(line);
  95. }
  96. else { // remaining lines contain a row key and data values
  97. extractRowKeyAndData(line, dataset, columnKeys);
  98. }
  99. line = reader.readLine();
  100. lineIndex++;
  101. }
  102. return dataset;
  103. }
  104. /**
  105. * Extracts the column keys from a string.
  106. *
  107. * @param line a line from the input file.
  108. *
  109. * @return A list of column keys.
  110. */
  111. private List extractColumnKeys(String line) {
  112. List keys = new java.util.ArrayList();
  113. int fieldIndex = 0;
  114. int start = 0;
  115. for (int i = 0; i < line.length(); i++) {
  116. if (line.charAt(i) == this.fieldDelimiter) {
  117. if (fieldIndex > 0) { // first field is ignored, since
  118. // column 0 is for row keys
  119. String key = line.substring(start, i);
  120. keys.add(removeStringDelimiters(key));
  121. }
  122. start = i + 1;
  123. fieldIndex++;
  124. }
  125. }
  126. String key = line.substring(start, line.length());
  127. keys.add(removeStringDelimiters(key));
  128. return keys;
  129. }
  130. /**
  131. * Extracts the row key and data for a single line from the input source.
  132. *
  133. * @param line the line from the input source.
  134. * @param dataset the dataset to be populated.
  135. * @param columnKeys the column keys.
  136. */
  137. private void extractRowKeyAndData(String line,
  138. DefaultCategoryDataset dataset,
  139. List columnKeys) {
  140. Comparable rowKey = null;
  141. int fieldIndex = 0;
  142. int start = 0;
  143. for (int i = 0; i < line.length(); i++) {
  144. if (line.charAt(i) == this.fieldDelimiter) {
  145. if (fieldIndex == 0) { // first field contains the row key
  146. String key = line.substring(start, i);
  147. rowKey = removeStringDelimiters(key);
  148. }
  149. else { // remaining fields contain values
  150. Double value = Double.valueOf(
  151. removeStringDelimiters(line.substring(start, i))
  152. );
  153. dataset.addValue(
  154. value, rowKey,
  155. (Comparable) columnKeys.get(fieldIndex - 1)
  156. );
  157. }
  158. start = i + 1;
  159. fieldIndex++;
  160. }
  161. }
  162. Double value = Double.valueOf(
  163. removeStringDelimiters(line.substring(start, line.length()))
  164. );
  165. dataset.addValue(
  166. value, rowKey, (Comparable) columnKeys.get(fieldIndex - 1)
  167. );
  168. }
  169. /**
  170. * Removes the string delimiters from a key (as well as any white space
  171. * outside the delimiters).
  172. *
  173. * @param key the key (including delimiters).
  174. *
  175. * @return The key without delimiters.
  176. */
  177. private String removeStringDelimiters(String key) {
  178. String k = key.trim();
  179. if (k.charAt(0) == this.textDelimiter) {
  180. k = k.substring(1);
  181. }
  182. if (k.charAt(k.length() - 1) == this.textDelimiter) {
  183. k = k.substring(0, k.length() - 1);
  184. }
  185. return k;
  186. }
  187. }