CSVデータの読み込み
RapidReportでは、データソースクラスを実装することによって、
どのような形式のデータでも帳票へ渡すことができます。
ここでは、例としてCSVファイルを読み込んでその内容を帳票に渡すデータソースを作成してみます。
完成したサンプルが example フォルダ内に以下の名前で含まれています。
データソースクラスのソースコード: CsvDataSource.cs、CsvDataSource.vb、CsvDataSource.java
帳票出力のソースコード: Example1csv.cs、Example1csv.vb、Example1csv.java
CSVデータ: report\data.csv
CSVファイルの形式
今回の例ではExcelで生成したCSVファイルを読み込めるように、
以下の形式のデータを解析可能なように実装します。
-
値の区切りをカンマ[,]、行の区切りを改行[CRLF]で表す
-
値にダブルクオート["]、カンマ[,]、改行が含まれる場合は、その値全体をダブルクオートで囲む
-
値が上記の文字を含まない場合は、ダブルクオートで囲む必要はない
-
値に含まれるダブルクオートは[""]で表す
-
値に含まれる改行は[LF]で表す
例えば次のようなデータの場合、
CSVファイルの内容は以下のようになります。
"あああ,いいい","改行を[LF]
含む"[CRLF]
"""ほげ""ふが",abcdef
CsvDataSourceクラスの実装
データソースクラスを作成するには、
以下のメソッドを含んだIReportDataSourceインターフェースを実装します。
メソッド |
説明 |
size() |
データの行数を返します
|
get(i, key) |
i行目のkey列の値を返します
|
帳票に渡されるデータはgetメソッドから戻り値として返すことになりますが、
今回の例では、データの形式が[yyyy/M/d]だった場合は日付型へと変換し、
数値として見なすことができる場合はDecimalまたはBigDecimalへと変換して返すものとします。
なお、CSVデータの最初の行には、列名が定義されているものとします。
CSVファイルを読み込むデータソースクラスをCsvDataSourceという名前で以下のように実装します。
(コードが長いため、折りたたみ表示にします)
▼C#のコードを開く
▲C#のコードを閉じる
public class CsvDataSource : IReportDataSource
{
private List<String> colNames;
private List<List<String>> rows = new List<List<String>>();
private static Regex dateRegex = new Regex("^\\d{4}/\\d{1,2}/\\d{1,2}$");
private static Regex numRegex = new Regex("^-?\\d+(\\.\\d*)?$");
public CsvDataSource(StreamReader r)
{
colNames = readCsv(r);
while(true){
List<String> row = readCsv(r);
if (row == null)
{
break;
}
else
{
rows.Add(row);
}
}
}
public int Size()
{
return this.rows.Count;
}
public object Get(int i, String key)
{
int j = colNames.IndexOf(key);
if (j == -1)
{
throw new UnknownFieldException(this, i, key);
}
else
{
return this.parseValue(this.rows[i][j]);
}
}
private List<String> readCsv(StreamReader r)
{
int c = r.Read();
if (c == -1)
{
return null;
}
List<String> ret = new List<String>();
StringBuilder sb = new StringBuilder();
Boolean q = false;
Boolean qe = false;
Boolean cr = false;
while(c != -1){
if (c == 0x22){
if (!q){
q = true;
}else if (!qe){
qe = true;
}else{
sb.Append("\"");
qe = false;
}
}else if (c == 0xd)
{
cr = true;
}else
{
if (qe){
q = false;
qe = false;
}
if (!q && cr && c == 0xA){
break;
}
cr = false;
if (!q && c == 0x2C)
{
ret.Add(sb.ToString());
sb = new StringBuilder();
}
else if (c == 0x0A)
{
if (q)
{
sb.Append("\r\n");
}
}
else
{
sb.Append(Convert.ToChar(c));
}
}
c = r.Read();
}
ret.Add(sb.ToString());
return ret;
}
private Object parseValue(String v)
{
try
{
if (v != null)
{
if (dateRegex.IsMatch(v)){
return DateTime.ParseExact(v, "yyyy/M/d", null);
}else if (numRegex.IsMatch(v)){
return Decimal.Parse(v);
}
}
}
catch (Exception) { }
return v;
}
}
▼VisualBasicのコードを開く
▲VisualBasicのコードを閉じる
Public Class CsvDataSource
Implements IReportDataSource
Private colNames As List(Of String)
Private rows As New List(Of List(Of String))
Private Shared dateRegex As New Regex("^\d{4}/\d{1,2}/\d{1,2}$")
Private Shared numRegex As New Regex("^-?\d+(\.\d*)?$")
Public Sub New(r As StreamReader)
colNames = readCsv(r)
Do
Dim row As List(Of String) = readCsv(r)
If row Is Nothing Then
Exit Do
Else
rows.Add(row)
End If
Loop
End Sub
Public Function Size() As Integer Implements IReportDataSource.Size
Return rows.Count
End Function
Public Function [Get](i As Integer, key As String) As Object Implements IReportDataSource.Get
Dim j As Integer = colNames.IndexOf(key)
If j = -1 Then
Throw New UnknownFieldException(Me, i, key)
Else
Return parseValue(rows(i)(j))
End If
End Function
Private Function readCsv(r As StreamReader) As List(Of String)
Dim c As Integer = r.Read()
If c = -1 Then
Return Nothing
End If
Dim ret As New List(Of String)
Dim sb As New StringBuilder
Dim q As Boolean = False
Dim qe As Boolean = False
Dim cr As Boolean = False
Do While c <> -1
If c = &H22 Then
If Not q Then
q = True
ElseIf Not qe Then
qe = True
Else
sb.Append("""")
qe = False
End If
ElseIf c = &HD Then
cr = True
Else
If qe Then
q = False
qe = False
End If
If Not q And cr And c = &HA Then
Exit Do
End If
cr = False
If Not q And c = &H2C Then
ret.Add(sb.ToString)
sb = New StringBuilder
ElseIf c = &HA Then
If q Then
sb.Append(vbCrLf)
End If
Else
sb.Append(Convert.ToChar(c))
End If
End If
c = r.Read()
Loop
ret.Add(sb.ToString)
Return ret
End Function
Private Function parseValue(v As String) As Object
Try
If v IsNot Nothing Then
If dateRegex.IsMatch(v) Then
Return DateTime.ParseExact(v, "yyyy/M/d", Nothing)
ElseIf numRegex.IsMatch(v) Then
Return Decimal.Parse(v)
End If
End If
Catch ex As Exception
End Try
Return v
End Function
End Class
▼Javaのコードを開く
▲Javaのコードを閉じる
public class CsvDataSource implements IReportDataSource{
private List<String> colNames;
private List<List<String>> rows = new ArrayList<List<String>>();
private static Pattern datePattern = Pattern.compile("^\\d{4}/\\d{1,2}/\\d{1,2}$");
private static Pattern numPattern = Pattern.compile("^-?\\d+(\\.\\d*)?$");
public CsvDataSource(Reader r) throws IOException{
colNames = readCsv(r);
while(true){
List<String> row = readCsv(r);
if (row == null){
break;
}else{
rows.add(row);
}
}
}
@Override
public int size() {
return rows.size();
}
@Override
public Object get(int i, String key) {
int j = colNames.indexOf(key);
if (j == -1){
throw new UnknownFieldException(this, i, key);
}else{
return parseValue(rows.get(i).get(j));
}
}
private List<String> readCsv(Reader r) throws IOException{
int c = r.read();
if (c == -1){
return null;
}
List<String> ret = new ArrayList<String>();
StringBuffer sb = new StringBuffer();
boolean q = false;
boolean qe = false;
boolean cr = false;
while(c != -1){
if (c == '"'){
if (!q){
q = true;
}else if (!qe){
qe = true;
}else{
sb.append("\"");
qe = false;
}
}else if (c == '\r'){
cr = true;
}else{
if (qe){
q = false;
qe = false;
}
if (!q && cr && c == '\n'){
break;
}
cr = false;
if (!q && c == ','){
ret.add(sb.toString());
sb = new StringBuffer();
}else if (c == '\n'){
if (q){
sb.append("\r\n");
}
}else{
sb.append((char)c);
}
}
c = r.read();
}
ret.add(sb.toString());
return ret;
}
private Object parseValue(String v){
try{
if (v != null){
if (datePattern.matcher(v).find()){
SimpleDateFormat df = new SimpleDateFormat("yyyy/M/d");
return df.parse(v);
}else if (numPattern.matcher(v).find()){
return new BigDecimal(v);
}
}
}catch(Exception e){
}
return v;
}
}
帳票へデータを渡す
CsvDataSourceオブジェクトは、reportオブジェクトのFillメソッドに渡すことで利用できます。
Report report = new Report(Json.Read("report\\example1.rrpt"));
using (StreamReader r = new StreamReader("report\\data.csv", Encoding.GetEncoding("shift-jis")))
{
report.Fill(new CsvDataSource(r));
}
...
Dim report As New Report(Json.Read("report\example1.rrpt"))
Using r = New StreamReader("report\data.csv", Encoding.GetEncoding("shift-jis"))
report.Fill(New CsvDataSource(r))
End Using
...
Report report = new Report(ReadUtil.readJson("report\\example1.rrpt"));
InputStream is = new FileInputStream("report\\data.csv");
try{
Reader r = new InputStreamReader(is, "shift-jis");
try{
report.fill(new CsvDataSource(r));
}finally{
r.close();
}
}finally{
is.close();
}
...
|