1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | |
|
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
|
33 | |
package net.sf.jmatchparser.util.csv; |
34 | |
|
35 | |
import java.io.IOException; |
36 | |
import java.io.InputStream; |
37 | |
import java.io.OutputStream; |
38 | |
import java.nio.charset.Charset; |
39 | |
import java.util.Arrays; |
40 | |
import java.util.HashSet; |
41 | |
import java.util.Properties; |
42 | |
import java.util.Set; |
43 | |
|
44 | |
import javax.xml.parsers.DocumentBuilderFactory; |
45 | |
|
46 | |
import org.w3c.dom.Document; |
47 | |
|
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
public class CSVFactory { |
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
|
70 | |
|
71 | |
|
72 | |
|
73 | |
|
74 | |
|
75 | |
|
76 | |
|
77 | |
|
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
|
83 | |
public static AbstractCSVReader createReader(InputStream in, String formatString) throws IOException { |
84 | 7 | return new CSVFactory(formatString, true).createReader(in); |
85 | |
} |
86 | |
|
87 | |
|
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
|
96 | |
|
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
|
102 | |
|
103 | |
|
104 | |
|
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | |
|
110 | |
|
111 | |
public static AbstractCSVWriter createWriter(OutputStream out, String formatString) throws IOException { |
112 | 5 | return new CSVFactory(formatString, false).createWriter(out); |
113 | |
} |
114 | |
|
115 | |
private final String charset; |
116 | |
private final Format format; |
117 | |
private final HashSet<String> flags; |
118 | |
private final char separatorChar; |
119 | |
private final FixedWidthColumn[] columns; |
120 | |
private final String rowString; |
121 | |
private final String[] columnStrings; |
122 | |
|
123 | 12 | private CSVFactory(String formatString, boolean forReader) { |
124 | 12 | String charset = null; |
125 | 12 | int pos = formatString.indexOf(", charset="); |
126 | 12 | if (pos != -1) { |
127 | 5 | charset = formatString.substring(pos + 10); |
128 | 5 | formatString = formatString.substring(0, pos); |
129 | |
} |
130 | 12 | flags = new HashSet<String>(); |
131 | 12 | pos = formatString.indexOf(", flags="); |
132 | 12 | if (pos != -1) { |
133 | 1 | flags.addAll(Arrays.asList(formatString.substring(pos + 8).split("\\+"))); |
134 | 1 | formatString = formatString.substring(0, pos); |
135 | |
} |
136 | |
final String[] supportedFlags; |
137 | |
final boolean charsetSupported; |
138 | 12 | if (formatString.startsWith("separator=")) { |
139 | 3 | String separatorName = formatString.substring(10); |
140 | 3 | if (separatorName.equals("auto") && forReader) { |
141 | 1 | separatorChar = 0; |
142 | 2 | } else if (separatorName.equals("comma")) { |
143 | 2 | separatorChar = ','; |
144 | 0 | } else if (separatorName.equals("semicolon")) { |
145 | 0 | separatorChar = ';'; |
146 | 0 | } else if (separatorName.equals("tab")) { |
147 | 0 | separatorChar = '\t'; |
148 | 0 | } else if (separatorName.length() == 1) { |
149 | 0 | separatorChar = separatorName.charAt(0); |
150 | |
} else { |
151 | 0 | throw new IllegalArgumentException("Unsupported separator: " + separatorName); |
152 | |
} |
153 | 3 | charsetSupported = true; |
154 | 3 | rowString = null; |
155 | 3 | columns = null; |
156 | 3 | columnStrings = null; |
157 | 3 | supportedFlags = forReader ? new String[] { "comments", "quotedlines", "multiline" } : new String[0]; |
158 | 3 | format = Format.CSV; |
159 | 3 | } else if (formatString.startsWith("fixed=")) { |
160 | 2 | String prefix = "", separator = "", suffix = ""; |
161 | 2 | pos = formatString.indexOf(", suffix="); |
162 | 2 | if (pos != -1) { |
163 | 0 | suffix = formatString.substring(pos + 9); |
164 | 0 | formatString = formatString.substring(0, pos); |
165 | |
} |
166 | 2 | pos = formatString.indexOf(", separator="); |
167 | 2 | if (pos != -1) { |
168 | 0 | separator = formatString.substring(pos + 12); |
169 | 0 | formatString = formatString.substring(0, pos); |
170 | |
} |
171 | 2 | pos = formatString.indexOf(", prefix="); |
172 | 2 | if (pos != -1) { |
173 | 0 | prefix = formatString.substring(pos + 9); |
174 | 0 | formatString = formatString.substring(0, pos); |
175 | |
} |
176 | 2 | columnStrings = new String[] { prefix, separator, suffix }; |
177 | 2 | String[] colSpecs = formatString.substring(6).split(","); |
178 | 2 | columns = new FixedWidthColumn[colSpecs.length]; |
179 | 6 | for (int i = 0; i < colSpecs.length; i++) { |
180 | 4 | columns[i] = FixedWidthColumn.parse(colSpecs[i]); |
181 | |
} |
182 | 2 | charsetSupported = true; |
183 | 2 | rowString = null; |
184 | 2 | separatorChar = 0; |
185 | 2 | supportedFlags = forReader ? new String[] { "comments" } : new String[] { "truncate" }; |
186 | 2 | format = Format.FIXED; |
187 | 2 | } else { |
188 | |
String[] parts; |
189 | 7 | if (formatString.startsWith("properties=")) { |
190 | 2 | parts = formatString.substring(11).split(",", 2); |
191 | 2 | format = Format.PROPERTIES; |
192 | 5 | } else if (formatString.startsWith("xml=")) { |
193 | 4 | parts = formatString.substring(4).split(",", 2); |
194 | 4 | format = Format.XML; |
195 | 1 | } else if (formatString.startsWith("xpath=") && forReader) { |
196 | 1 | parts = formatString.substring(6).split(",", 2); |
197 | 1 | format = Format.XPATH; |
198 | |
} else { |
199 | 0 | throw new IllegalArgumentException("Unparsable format string: " + formatString); |
200 | |
} |
201 | 7 | rowString = parts[0]; |
202 | 7 | columnStrings = parts[1].split(","); |
203 | 7 | charsetSupported = false; |
204 | 7 | supportedFlags = new String[0]; |
205 | 7 | columns = null; |
206 | 7 | separatorChar = 0; |
207 | |
} |
208 | |
|
209 | 12 | if (charsetSupported) { |
210 | 5 | if (charset == null) |
211 | 0 | charset = "UTF-BOM." + Charset.defaultCharset().name(); |
212 | 7 | } else if (charset != null) { |
213 | 0 | throw new IllegalArgumentException("Charset not supported for this format"); |
214 | |
} |
215 | 12 | this.charset = charset; |
216 | 12 | Set<String> supportedFlagsSet = new HashSet<String>(); |
217 | 12 | supportedFlagsSet.addAll(Arrays.asList(supportedFlags)); |
218 | 12 | for (String flag : flags) { |
219 | 2 | if (!supportedFlagsSet.contains(flag)) |
220 | 0 | throw new IllegalArgumentException("Unsupported flag: " + flag); |
221 | |
} |
222 | 12 | } |
223 | |
|
224 | |
private AbstractCSVReader createReader(InputStream in) throws IOException { |
225 | 7 | switch (format) { |
226 | |
case CSV: { |
227 | 2 | CSVReader r = new CSVReader(in, charset); |
228 | 2 | r.setSeparator(separatorChar); |
229 | 2 | r.setStripComments(flags.contains("comments")); |
230 | 2 | r.setSupportFullyQuotedLines(flags.contains("quotedlines")); |
231 | 2 | r.setSupportMultiLineCells(flags.contains("multiline")); |
232 | 2 | return r; |
233 | |
} |
234 | |
case FIXED: { |
235 | 1 | final String prefix = columnStrings[0], separator = columnStrings[1], suffix = columnStrings[2]; |
236 | 1 | FixedWidthCSVReader r = new FixedWidthCSVReader(in, charset, prefix, separator, suffix, columns); |
237 | 1 | r.setStripComments(flags.contains("comments")); |
238 | 1 | return r; |
239 | |
} |
240 | |
case PROPERTIES: { |
241 | 1 | Properties props = new Properties(); |
242 | 1 | props.load(in); |
243 | 1 | in.close(); |
244 | 1 | return new PropertiesCSVReader(props, Integer.parseInt(rowString), columnStrings); |
245 | |
} |
246 | |
case XML: { |
247 | |
try { |
248 | 2 | Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in); |
249 | 2 | return new XMLCSVReader(doc, rowString, columnStrings); |
250 | 0 | } catch (Exception ex) { |
251 | 0 | throw new IOException("Exception while parsing XML file", ex); |
252 | |
} |
253 | |
} |
254 | |
case XPATH: { |
255 | |
try { |
256 | 1 | Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in); |
257 | 1 | return new XPathCSVReader(doc, rowString, columnStrings); |
258 | 0 | } catch (Exception ex) { |
259 | 0 | throw new IOException("Exception while parsing XML file", ex); |
260 | |
} |
261 | |
} |
262 | |
default: |
263 | 0 | throw new IOException("Unsupported CSV format"); |
264 | |
} |
265 | |
} |
266 | |
|
267 | |
private AbstractCSVWriter createWriter(OutputStream out) throws IOException { |
268 | 5 | switch (format) { |
269 | |
case CSV: { |
270 | 1 | return new CSVWriter(out, charset, separatorChar); |
271 | |
} |
272 | |
case FIXED: { |
273 | 1 | final String prefix = columnStrings[0], separator = columnStrings[1], suffix = columnStrings[2]; |
274 | 1 | FixedWidthCSVWriter w = new FixedWidthCSVWriter(out, charset, prefix, separator, suffix, columns); |
275 | 1 | w.setTruncateValues(flags.contains("truncate")); |
276 | 1 | return w; |
277 | |
} |
278 | |
case PROPERTIES: { |
279 | 1 | return new PropertiesCSVWriter(out, Integer.parseInt(rowString), columnStrings); |
280 | |
} |
281 | |
case XML: { |
282 | |
try { |
283 | 2 | return new XMLCSVWriter(out, "csv", rowString, columnStrings); |
284 | 0 | } catch (Exception ex) { |
285 | 0 | throw new IOException("Exception while creating XML file", ex); |
286 | |
} |
287 | |
} |
288 | |
default: |
289 | 0 | throw new IOException("Unsupported CSV format"); |
290 | |
} |
291 | |
} |
292 | |
|
293 | 7 | private enum Format { |
294 | 1 | CSV, FIXED, PROPERTIES, XML, XPATH |
295 | |
} |
296 | |
} |