Skip to content

Commit 4c70477

Browse files
committed
Added csv2json cli
1 parent 997c7fe commit 4c70477

File tree

3 files changed

+195
-2
lines changed

3 files changed

+195
-2
lines changed

Makefile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ VERSION = $(shell grep -m1 'Version = ' $(PROJECT).go | cut -d\" -f 2)
77

88
BRANCH = $(shell git branch | grep '* ' | cut -d\ -f 2)
99

10-
build: bin/csvcols bin/csvjoin bin/jsoncols bin/jsonrange bin/xlsx2json bin/xlsx2csv bin/csv2mdtable bin/csv2xlsx
10+
build: bin/csvcols bin/csvjoin bin/jsoncols bin/jsonrange bin/xlsx2json bin/xlsx2csv bin/csv2mdtable bin/csv2xlsx bin/csv2json
1111

1212
bin/csvcols: datatools.go cmds/csvcols/csvcols.go
1313
go build -o bin/csvcols cmds/csvcols/csvcols.go
@@ -33,6 +33,9 @@ bin/csv2mdtable: datatools.go cmds/csv2mdtable/csv2mdtable.go
3333
bin/csv2xlsx: datatools.go cmds/csv2xlsx/csv2xlsx.go
3434
go build -o bin/csv2xlsx cmds/csv2xlsx/csv2xlsx.go
3535

36+
bin/csv2json: datatools.go cmds/csv2json/csv2json.go
37+
go build -o bin/csv2json cmds/csv2json/csv2json.go
38+
3639
test:
3740
cd dotpath && go test
3841

@@ -68,6 +71,7 @@ install:
6871
env GOBIN=$(HOME)/bin go install cmds/xlsx2csv/xlsx2csv.go
6972
env GOBIN=$(HOME)/bin go install cmds/csv2mdtable/csv2mdtable.go
7073
env GOBIN=$(HOME)/bin go install cmds/csv2xlsx/csv2xlsx.go
74+
env GOBIN=$(HOME)/bin go install cmds/csv2json/csv2json.go
7175

7276
dist/linux-amd64:
7377
env GOOS=linux GOARCH=amd64 go build -o dist/linux-amd64/csvcols cmds/csvcols/csvcols.go
@@ -78,6 +82,7 @@ dist/linux-amd64:
7882
env GOOS=linux GOARCH=amd64 go build -o dist/linux-amd64/xlsx2csv cmds/xlsx2csv/xlsx2csv.go
7983
env GOOS=linux GOARCH=amd64 go build -o dist/linux-amd64/csv2mdtable cmds/csv2mdtable/csv2mdtable.go
8084
env GOOS=linux GOARCH=amd64 go build -o dist/linux-amd64/csv2xlsx cmds/csv2xlsx/csv2xlsx.go
85+
env GOOS=linux GOARCH=amd64 go build -o dist/linux-amd64/csv2json cmds/csv2json/csv2json.go
8186

8287
dist/macosx-amd64:
8388
env GOOS=darwin GOARCH=amd64 go build -o dist/macosx-amd64/csvcols cmds/csvcols/csvcols.go
@@ -88,6 +93,7 @@ dist/macosx-amd64:
8893
env GOOS=darwin GOARCH=amd64 go build -o dist/macosx-amd64/xlsx2csv cmds/xlsx2csv/xlsx2csv.go
8994
env GOOS=darwin GOARCH=amd64 go build -o dist/macosx-amd64/csv2mdtable cmds/csv2mdtable/csv2mdtable.go
9095
env GOOS=darwin GOARCH=amd64 go build -o dist/macosx-amd64/csv2xlsx cmds/csv2xlsx/csv2xlsx.go
96+
env GOOS=darwin GOARCH=amd64 go build -o dist/macosx-amd64/csv2json cmds/csv2json/csv2json.go
9197

9298
dist/windows-amd64:
9399
env GOOS=windows GOARCH=amd64 go build -o dist/windows-amd64/csvcols.exe cmds/csvcols/csvcols.go
@@ -98,6 +104,7 @@ dist/windows-amd64:
98104
env GOOS=windows GOARCH=amd64 go build -o dist/windows-amd64/xlsx2csv.exe cmds/xlsx2csv/xlsx2csv.go
99105
env GOOS=windows GOARCH=amd64 go build -o dist/windows-amd64/csv2mdtable.exe cmds/csv2mdtable/csv2mdtable.go
100106
env GOOS=windows GOARCH=amd64 go build -o dist/windows-amd64/csv2xlsx.exe cmds/csv2xlsx/csv2xlsx.go
107+
env GOOS=windows GOARCH=amd64 go build -o dist/windows-amd64/csv2json.exe cmds/csv2json/csv2json.go
101108

102109
dist/raspbian-arm7:
103110
env GOOS=linux GOARCH=arm GOARM=7 go build -o dist/raspbian-arm7/csvcols cmds/csvcols/csvcols.go
@@ -108,6 +115,7 @@ dist/raspbian-arm7:
108115
env GOOS=linux GOARCH=arm GOARM=7 go build -o dist/raspbian-arm7/xlsx2csv cmds/xlsx2csv/xlsx2csv.go
109116
env GOOS=linux GOARCH=arm GOARM=7 go build -o dist/raspbian-arm7/csv2mdtable cmds/csv2mdtable/csv2mdtable.go
110117
env GOOS=linux GOARCH=arm GOARM=7 go build -o dist/raspbian-arm7/csv2xlsx cmds/csv2xlsx/csv2xlsx.go
118+
env GOOS=linux GOARCH=arm GOARM=7 go build -o dist/raspbian-arm7/csv2json cmds/csv2json/csv2json.go
111119

112120
release: dist/linux-amd64 dist/macosx-amd64 dist/windows-amd64 dist/raspbian-arm7
113121
mkdir -p dist
@@ -122,5 +130,6 @@ release: dist/linux-amd64 dist/macosx-amd64 dist/windows-amd64 dist/raspbian-arm
122130
cp -v xlsx2csv.md dist/
123131
cp -v csv2mdtable.md dist/
124132
cp -v csv2xlsx.md dist/
133+
cp -v csv2json.md dist/
125134
zip -r $(PROJECT)-$(VERSION)-release.zip dist/
126135

cmds/csv2json/csv2json.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
//
2+
// csv2json - is a command line that takes CSV input from stdin and
3+
// writes out JSON expression. It includes support for using the first
4+
// row as field names or default fieldnames (e.g. col0, col1, col2).
5+
// Additionally it can output the resulting JSON data structures as a
6+
// JSON array or individual JSON blobs (one line per blob).
7+
//
8+
// @author R. S. Doiel, <[email protected]>
9+
//
10+
// Copyright (c) 2017, Caltech
11+
// All rights not granted herein are expressly reserved by Caltech.
12+
//
13+
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
14+
//
15+
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
16+
//
17+
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
18+
//
19+
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
20+
//
21+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22+
//
23+
package main
24+
25+
import (
26+
"encoding/csv"
27+
"encoding/json"
28+
"flag"
29+
"fmt"
30+
"io"
31+
"os"
32+
"path"
33+
"strings"
34+
35+
// My packages
36+
"github.com/caltechlibrary/cli"
37+
"github.com/caltechlibrary/datatools"
38+
)
39+
40+
var (
41+
usage = `USAGE: %s [OPTIONS]`
42+
43+
description = `
44+
SYNOPSIS
45+
46+
%s reads CSV from stdin and writes a JSON to stdout. JSON output
47+
can be either an array of JSON blobs or one JSON blob (row as object)
48+
per line.
49+
`
50+
51+
examples = `
52+
EXAMPLES
53+
54+
Convert data1.csv to data1.json using Unix pipes.
55+
56+
cat data1.csv | %s > data1.json
57+
58+
Convert data1.csv to JSON blobs, one line per blob
59+
60+
%s -as-blobs -i data1.csv
61+
`
62+
63+
// Standard Options
64+
showHelp bool
65+
showLicense bool
66+
showVersion bool
67+
inputFName string
68+
outputFName string
69+
70+
// Application Options
71+
useHeader bool
72+
asBlobs bool
73+
)
74+
75+
func init() {
76+
// Standard Options
77+
flag.BoolVar(&showHelp, "h", false, "display help")
78+
flag.BoolVar(&showHelp, "help", false, "display help")
79+
flag.BoolVar(&showLicense, "l", false, "display license")
80+
flag.BoolVar(&showLicense, "license", false, "display license")
81+
flag.BoolVar(&showVersion, "v", false, "display version")
82+
flag.BoolVar(&showVersion, "version", false, "display version")
83+
flag.StringVar(&inputFName, "i", "", "input filename")
84+
flag.StringVar(&inputFName, "input", "", "input filename")
85+
flag.StringVar(&outputFName, "o", "", "output filename")
86+
flag.StringVar(&outputFName, "output", "", "output filename")
87+
88+
// App Options
89+
flag.BoolVar(&useHeader, "use-header", true, "treat the first row as field names")
90+
flag.BoolVar(&asBlobs, "as-blobs", false, "output as one JSON blob per line")
91+
}
92+
93+
func main() {
94+
appName := path.Base(os.Args[0])
95+
flag.Parse()
96+
97+
// Configuration and command line interation
98+
cfg := cli.New(appName, appName, fmt.Sprintf(datatools.LicenseText, appName, datatools.Version), datatools.Version)
99+
cfg.UsageText = fmt.Sprintf(usage, appName)
100+
cfg.DescriptionText = fmt.Sprintf(description, appName)
101+
cfg.ExampleText = fmt.Sprintf(examples, appName, appName)
102+
103+
if showHelp == true {
104+
fmt.Println(cfg.Usage())
105+
os.Exit(0)
106+
}
107+
108+
if showLicense == true {
109+
fmt.Println(cfg.License())
110+
os.Exit(0)
111+
}
112+
113+
if showVersion == true {
114+
fmt.Println(cfg.Version())
115+
os.Exit(0)
116+
}
117+
118+
in, err := cli.Open(inputFName, os.Stdin)
119+
if err != nil {
120+
fmt.Fprintf(os.Stderr, "%s\n", err)
121+
os.Exit(1)
122+
}
123+
defer cli.CloseFile(inputFName, in)
124+
125+
out, err := cli.Create(outputFName, os.Stdout)
126+
if err != nil {
127+
fmt.Fprintf(os.Stderr, "%s\n", err)
128+
os.Exit(1)
129+
}
130+
defer cli.CloseFile(outputFName, out)
131+
132+
rowNo := 0
133+
fieldNames := []string{}
134+
r := csv.NewReader(in)
135+
if useHeader == true {
136+
row, err := r.Read()
137+
if err == io.EOF {
138+
fmt.Fprintf(os.Stderr, "No data\n")
139+
os.Exit(1)
140+
}
141+
if err != nil {
142+
fmt.Fprintf(os.Stderr, "%s\n", err)
143+
os.Exit(1)
144+
}
145+
for _, val := range row {
146+
fieldNames = append(fieldNames, strings.TrimSpace(val))
147+
}
148+
rowNo++
149+
}
150+
arrayOfObjects := []string{}
151+
object := map[string]interface{}{}
152+
for {
153+
row, err := r.Read()
154+
if err == io.EOF {
155+
break
156+
}
157+
if err != nil {
158+
fmt.Fprintf(os.Stderr, "%s\n", err)
159+
os.Exit(1)
160+
}
161+
// Pad the fieldnames if necessary
162+
object = map[string]interface{}{}
163+
for col, val := range row {
164+
if col < len(fieldNames) {
165+
object[fieldNames[col]] = val
166+
} else {
167+
object[fmt.Sprintf("col_%d", col)] = val
168+
}
169+
}
170+
src, err := json.Marshal(object)
171+
if err != nil {
172+
fmt.Fprintf(os.Stderr, "error row %d, %s\n", rowNo, err)
173+
}
174+
if asBlobs == true {
175+
fmt.Fprintf(os.Stdout, "%s\n", src)
176+
} else {
177+
arrayOfObjects = append(arrayOfObjects, string(src))
178+
}
179+
rowNo++
180+
}
181+
if asBlobs == false {
182+
fmt.Fprintf(os.Stdout, "[%s]\n", strings.Join(arrayOfObjects, ","))
183+
}
184+
}

datatools.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
package datatools
88

99
const (
10-
Version = "v0.0.4"
10+
Version = "v0.0.5"
1111

1212
LicenseText = `
1313
%s %s

0 commit comments

Comments
 (0)