//
// Copyright (c) 2012, Brian Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 29 Sep 2012 Brian Frank Creation
//
package org.haystack.io;
import java.io.OutputStream;
import java.io.Writer;
import org.haystack.HCol;
import org.haystack.HDict;
import org.haystack.HRow;
import org.haystack.tagval.HMarker;
import org.haystack.tagval.HRef;
import org.haystack.tagval.HVal;
/**
* HCsvWriter is used to write grids in comma separated values
* format as specified by RFC 4180. Format details:
* <ul>
* <li>rows are delimited by a newline</li>
* <li>cells are separated by configured delimiter char (default is comma)</li>
* <li>cells containing the delimiter, '"' double quote, or newline are quoted; quotes are escaped as with two quotes</li>
* </ul>
*
* @see <a href='http://project-haystack.org/doc/Csv'>Project Haystack</a>
*/
public class HCsvWriter extends HGridWriter {
/** Delimiter used to write each cell */
public char delimiter = ',';
//////////////////////////////////////////////////////////////////////////
// Construction
//////////////////////////////////////////////////////////////////////////
public HCsvWriter(OutputStream out) {
super(out);
}
public HCsvWriter(Writer out) {
super(out);
}
//////////////////////////////////////////////////////////////////////////
// HGridWriter
//////////////////////////////////////////////////////////////////////////
@Override
public void writeMeta(HDict meta) {
// no op
}
@Override
public void writeCols(HCol[] cols) {
for (int i = 0; i < cols.length; ++i) {
if (i > 0)
out.write(delimiter);
writeCell(cols[i].dis());
}
out.write('\n');
}
@Override
public void writeRow(HCol[] cols, HRow row, int index) {
for (int i = 0; i < cols.length; ++i) {
HVal val = row.get(cols[i], false);
if (i > 0)
out.write(delimiter);
writeCell(valToString(val));
}
out.write('\n');
}
private String valToString(HVal val) {
if (val == null)
return "";
if (val == HMarker.VAL)
return "\u2713";
if (val instanceof HRef) {
HRef ref = (HRef) val;
String s = "@" + ref.val;
if (ref.dis != null)
s += " " + ref.dis;
return s;
}
return val.toString();
}
//////////////////////////////////////////////////////////////////////////
// CSV
//////////////////////////////////////////////////////////////////////////
/** Write a cell */
public void writeCell(String cell) {
if (!isQuoteRequired(cell)) {
out.print(cell);
}
else {
out.print('"');
for (int i = 0; i < cell.length(); ++i) {
int c = cell.charAt(i);
if (c == '"')
out.print('"');
out.print((char) c);
}
out.print('"');
}
}
/**
* Return if the given cell string contains:
* <ul>
* <li>the configured delimiter</li>
* <li>double quote '"' char</li>
* <li>leading/trailing whitespace</li>
* <li>newlines</li>
* </ul>
*/
public boolean isQuoteRequired(String cell) {
if (cell.length() == 0)
return true;
if (isWhiteSpace(cell.charAt(0)))
return true;
if (isWhiteSpace(cell.charAt(cell.length() - 1)))
return true;
for (int i = 0; i < cell.length(); ++i) {
int c = cell.charAt(i);
if (c == delimiter || c == '"' || c == '\n' || c == '\r')
return true;
}
return false;
}
static boolean isWhiteSpace(int c) {
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}
}