@@ -22,20 +22,38 @@ import (
22
22
)
23
23
24
24
var (
25
- usage = `USAGE: %s [OPTIONS] JSON_FILE_1 JSON_FILE_2`
25
+ usage = `USAGE: %s [OPTIONS] JSON_FILE_1 [ JSON_FILE_2 ...] `
26
26
27
27
description = `
28
28
SYSNOPSIS
29
29
30
- %s is a command line tool that takes two (or more) JSON object
31
- documents and combines into a new JSON object document based on
32
- the options chosen.
30
+ %s is a command line tool that takes one (or more) JSON objects files
31
+ and joins them to a root JSON object read from standard input (or
32
+ file identified by -input option). By default the resulting
33
+ joined JSON object is written to standard out.
34
+
35
+ The default behavior for %s is to create key/value pairs
36
+ based on the joined JSON document names and their contents.
37
+ This can be thought of as a branching behavior. Each additional
38
+ file becomes a branch and its key/value pairs become leafs.
39
+ The root JSON object is assumed to come from standard input
40
+ but can be designated by the -input option or created by the
41
+ -create option. Each additional file specified as a command line
42
+ argument is then treated as a new branch.
43
+
44
+ In addition to the branching behavior you can join JSON objects in a
45
+ flat manner. The flat joining process can be ether non-distructive
46
+ adding new key/value pairs (-update option) or distructive
47
+ overwriting key/value pairs (-overwrite option).
48
+
49
+ Note: %s doesn't support a JSON array as the root JSON object.
33
50
`
34
51
35
52
examples = `
36
53
EXAMPLES
37
54
38
- Joining two JSON objects (maps)
55
+ Consider two JSON objects one in person.json and another
56
+ in profile.json.
39
57
40
58
person.json containes
41
59
@@ -46,28 +64,47 @@ profile.json containes
46
64
{ "name": "Doe, Jane", "bio": "World renowned geophysist.",
47
65
48
66
49
- A simple join of person.json with profile.json
67
+ A simple join of person.json with profile.json (note the
68
+ -create option)
50
69
51
- %s person.json profile.json
70
+ %s -create person.json profile.json
52
71
53
- would yeild
72
+ would yeild and object like
54
73
55
74
{
56
- "person": { "name": "Doe, Jane", "email":"[email protected] ", "age": 42},
75
+ "person": { "name": "Doe, Jane", "email":"[email protected] ",
76
+ "age": 42},
77
+ "profile": { "name": "Doe, Jane", "bio": "World renowned geophysist.",
78
+
79
+ }
80
+
81
+ Likewise if you want to treat person.json as the root object and add
82
+ profile.json as a branch try
83
+
84
+ cat person.json | %s profile.json
85
+
86
+ or
87
+
88
+ %s -i person.json profile.json
89
+
90
+ this yields an object like
91
+
92
+ {
93
+ "name": "Doe, Jane", "email":"[email protected] ", "age": 42,
57
94
"profile": { "name": "Doe, Jane", "bio": "World renowned geophysist.",
58
95
59
96
}
60
97
61
98
You can modify this behavor with -update or -overwrite. Both options are
62
- order dependant (e.g . not associative, A update B does
99
+ order dependant (i.e . not associative, A update B does
63
100
not necessarily equal B update A).
64
101
65
102
+ -update will add unique key/values from the second object to the first object
66
103
+ -overwrite replace key/values in first object one with second objects'
67
104
68
105
Running
69
106
70
- %s -update person.json profile.json
107
+ %s -create - update person.json profile.json
71
108
72
109
would yield
73
110
@@ -76,7 +113,7 @@ would yield
76
113
77
114
Running
78
115
79
- %s -update profile.json person.json
116
+ %s -create - update profile.json person.json
80
117
81
118
would yield
82
119
@@ -86,7 +123,7 @@ would yield
86
123
87
124
Running
88
125
89
- %s -overwrite person.json profile.json
126
+ %s -create - overwrite person.json profile.json
90
127
91
128
would yield
92
129
@@ -98,11 +135,13 @@ would yield
98
135
showHelp bool
99
136
showLicense bool
100
137
showVersion bool
138
+ inputFName string
101
139
outputFName string
102
140
103
141
// Application Specific Options
104
- update bool
105
- overwrite bool
142
+ update bool
143
+ overwrite bool
144
+ createRoot bool
106
145
)
107
146
108
147
func init () {
@@ -113,12 +152,15 @@ func init() {
113
152
flag .BoolVar (& showLicense , "license" , false , "display license" )
114
153
flag .BoolVar (& showVersion , "v" , false , "display version" )
115
154
flag .BoolVar (& showVersion , "version" , false , "display version" )
155
+ flag .StringVar (& inputFName , "i" , "" , "input filename (for root object)" )
156
+ flag .StringVar (& inputFName , "input" , "" , "input filename (for root object)" )
116
157
flag .StringVar (& outputFName , "o" , "" , "output filename" )
117
158
flag .StringVar (& outputFName , "output" , "" , "output filename" )
118
159
119
160
// Application Specific Options
120
- flag .BoolVar (& update , "update" , false , "copy unique key/values from second object into the first" )
121
- flag .BoolVar (& overwrite , "overwrite" , false , "copy all key/values from second object into the first" )
161
+ flag .BoolVar (& createRoot , "create" , false , "create an empty root object, {}" )
162
+ flag .BoolVar (& update , "update" , false , "copy new key/values pairs into root object" )
163
+ flag .BoolVar (& overwrite , "overwrite" , false , "copy all key/values into root object" )
122
164
}
123
165
124
166
func main () {
@@ -129,8 +171,8 @@ func main() {
129
171
// Configuration and command line interation
130
172
cfg := cli .New (appName , "DATATOOLS" , fmt .Sprintf (datatools .LicenseText , appName , datatools .Version ), datatools .Version )
131
173
cfg .UsageText = fmt .Sprintf (usage , appName )
132
- cfg .DescriptionText = fmt .Sprintf (description , appName )
133
- cfg .ExampleText = fmt .Sprintf (examples , appName , appName , appName , appName )
174
+ cfg .DescriptionText = fmt .Sprintf (description , appName , appName , appName )
175
+ cfg .ExampleText = fmt .Sprintf (examples , appName , appName , appName , appName , appName , appName )
134
176
135
177
if showHelp == true {
136
178
fmt .Println (cfg .Usage ())
@@ -152,21 +194,42 @@ func main() {
152
194
os .Exit (1 )
153
195
}
154
196
197
+ in , err := cli .Open (inputFName , os .Stdin )
198
+ if err != nil {
199
+ fmt .Fprintf (os .Stderr , "%s\n " , err )
200
+ os .Exit (1 )
201
+ }
202
+ defer cli .CloseFile (inputFName , in )
203
+
155
204
out , err := cli .Create (outputFName , os .Stdout )
156
205
if err != nil {
157
206
fmt .Fprintf (os .Stderr , "%s\n " , err )
158
207
os .Exit (1 )
159
208
}
160
209
defer cli .CloseFile (outputFName , out )
161
210
162
- if len (args ) < 2 {
163
- fmt .Println (cfg .Usage ())
211
+ // Make sure we have some JSON objects to join...
212
+ if len (args ) < 1 {
213
+ fmt .Fprintln (os .Stderr , cfg .Usage ())
214
+ fmt .Fprintln (os .Stderr , "Missing JSON document(s) to join" )
164
215
os .Exit (1 )
165
216
}
166
217
167
218
outObject := map [string ]interface {}{}
168
219
newObject := map [string ]interface {}{}
169
220
221
+ // READ in the JSON document if present on standard in or specified with -i.
222
+ if createRoot == false {
223
+ buf , err := ioutil .ReadAll (in )
224
+ if err != nil {
225
+ fmt .Fprintf (os .Stderr , "%s\n " , err )
226
+ os .Exit (1 )
227
+ }
228
+ if err := json .Unmarshal (buf , & outObject ); err != nil {
229
+ log .Fatal (err )
230
+ }
231
+ }
232
+
170
233
for _ , arg := range args {
171
234
src , err := ioutil .ReadFile (arg )
172
235
if err != nil {
0 commit comments