forked from clbanning/mxj
-
Notifications
You must be signed in to change notification settings - Fork 0
/
example_test.go
356 lines (309 loc) · 10.1 KB
/
example_test.go
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
84
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
// +test OMIT
// note - "// Output:" is a key for "go test" to match function ouput with the lines that follow.
// It is also use by "godoc" to build the Output block of the function / method documentation.
// To skip processing Example* functions, use: go test -run "Test*"
// or make sure example function output matches // Output: documentation EXACTLY.
package mxj_test
import (
/*
"bytes"
"fmt"
"github.com/clbanning/mxj"
"io"
*/
)
func ExampleHandleXmlReader() {
/*
Bulk processing XML to JSON seems to be a common requirement.
See: bulk_test.go for working example.
Run "go test" in package directory then scroll back to find output.
The logic is as follows.
// need somewhere to write the JSON.
var jsonWriter io.Writer
// probably want to log any errors in reading the XML stream
var xmlErrLogger io.Writer
// func to handle Map value from XML Reader
func maphandler(m mxj.Map) bool {
// marshal Map as JSON
jsonVal, err := m.Json()
if err != nil {
// log error
return false // stops further processing of XML Reader
}
// write JSON somewhere
_, err = jsonWriter.Write(jsonVal)
if err != nil {
// log error
return false // stops further processing of XML Reader
}
// continue - get next XML from Reader
return true
}
// func to handle error from unmarshaling XML Reader
func errhandler(errVal error) bool {
// log error somewhere
_, err := xmlErrLogger.Write([]byte(errVal.Error()))
if err != nil {
// log error
return false // stops further processing of XML Reader
}
// continue processing
return true
}
// func that starts bulk processing of the XML
...
// set up io.Reader for XML data - perhaps an os.File
...
err := mxj.HandleXmlReader(xmlReader, maphandler, errhandler)
if err != nil {
// handle error
}
...
*/
}
func ExampleHandleXmlReaderRaw() {
/*
See: bulkraw_test.go for working example.
Run "go test" in package directory then scroll back to find output.
Basic logic for bulk XML to JSON processing is in HandleXmlReader example;
the only major difference is in handler function signatures so they are passed
the raw XML. (Read documentation on NewXmlReader regarding performance.)
*/
}
func ExampleHandleJsonReader() {
/*
See: bulk_test.go for working example.
Run "go test" in package directory then scroll back to find output.
Basic logic for bulk JSON to XML processing is similar to that for
bulk XML to JSON processing as outlined in the HandleXmlReader example.
The test case is also a good example.
*/
}
func ExampleHandleJsonReaderRaw() {
/*
See: bulkraw_test.go for working example.
Run "go test" in package directory then scroll back to find output.
Basic logic for bulk JSON to XML processing is similar to that for
bulk XML to JSON processing as outlined in the HandleXmlReader example.
The test case is also a good example.
*/
}
/*
func ExampleNewMapXmlReaderRaw() {
// in an http.Handler
mapVal, raw, err := mxj.NewMapXmlReader(req.Body)
if err != nil {
// handle error
}
logger.Print(string(*raw))
// do something with mapVal
}
*/
/*
func ExampleNewMapStruct() {
type str struct {
IntVal int `structs:"int"`
StrVal string `structs:"str"`
FloatVal float64 `structs:"float"`
BoolVal bool `structs:"bool"`
private string
}
strVal := str{IntVal: 4, StrVal: "now's the time", FloatVal: 3.14159, BoolVal: true, private: "Skies are blue"}
mapVal, merr := mxj.NewMapStruct(strVal)
if merr != nil {
// handle error
}
fmt.Printf("strVal: %#v\n", strVal)
fmt.Printf("mapVal: %#v\n", mapVal)
// Note: example output is conformed to pass "go test". "mxj_test" is example_test.go package name.
// NoFail output:
// strVal: mxj_test.str{IntVal:4, StrVal:"now's the time", FloatVal:3.14159, BoolVal:true, private:"Skies are blue"}
// mapVal: mxj.Map{"float":3.14159, "bool":true, "int":4, "str":"now's the time"}
}
*/
func ExampleMap_Struct() {
/*
type str struct {
IntVal int `json:"int"`
StrVal string `json:"str"`
FloatVal float64 `json:"float"`
BoolVal bool `json:"bool"`
private string
}
mapVal := mxj.Map{"int": 4, "str": "now's the time", "float": 3.14159, "bool": true, "private": "Somewhere over the rainbow"}
var strVal str
mverr := mapVal.Struct(&strVal)
if mverr != nil {
// handle error
}
fmt.Printf("mapVal: %#v\n", mapVal)
fmt.Printf("strVal: %#v\n", strVal)
// Unordered output for above:
// mapVal: mxj.Map{"int":4, "str":"now's the time", "float":3.14159, "bool":true, "private":"Somewhere over the rainbow"}
// strVal: mxj_test.str{IntVal:4, StrVal:"now's the time", FloatVal:3.14159, BoolVal:true, private:""}
*/
}
func ExampleMap_ValuesForPath() {
/*
// a snippet from examples/gonuts1.go
// How to compensate for irregular tag labels in data.
// Need to extract from an XML stream the values for "netid" and "idnet".
// Solution: use a wildcard path "data.*" to anonymize the "netid" and "idnet" tags.
var msg1 = []byte(`
<?xml version="1.0" encoding="UTF-8"?>
<data>
<netid>
<disable>no</disable>
<text1>default:text</text1>
<word1>default:word</word1>
</netid>
</data>
`)
var msg2 = []byte(`
<?xml version="1.0" encoding="UTF-8"?>
<data>
<idnet>
<disable>yes</disable>
<text1>default:text</text1>
<word1>default:word</word1>
</idnet>
</data>
`)
// let's create a message stream
buf := new(bytes.Buffer)
// load a couple of messages into it
_, _ = buf.Write(msg1)
_, _ = buf.Write(msg2)
n := 0
for {
n++
// Read the stream as Map values - quit on io.EOF.
// Get the raw XML as well as the Map value.
m, merr := mxj.NewMapXmlReader(buf)
if merr != nil && merr != io.EOF {
// handle error - for demo we just print it and continue
fmt.Printf("msg: %d - merr: %s\n", n, merr.Error())
continue
} else if merr == io.EOF {
break
}
// get the values for "netid" or "idnet" key using path == "data.*"
values, _ := m.ValuesForPath("data.*")
fmt.Println("\nmsg:", n, "> path == data.* - got array of values, len:", len(values))
for i, val := range values {
fmt.Println("ValuesForPath result array member -", i, ":", val)
fmt.Println(" k:v pairs for array member:", i)
for key, val := range val.(map[string]interface{}) {
// You'd probably want to process the value, as appropriate.
// Here we just print it out.
fmt.Println("\t\t", key, ":", val)
}
}
}
// NoFail output:
// msg: 1 > path == data.* - got array of values, len: 1
// ValuesForPath result array member - 0 : map[disable:no text1:default:text word1:default:word]
// k:v pairs for array member: 0
// disable : no
// text1 : default:text
// word1 : default:word
//
// msg: 2 > path == data.* - got array of values, len: 1
// ValuesForPath result array member - 0 : map[disable:yes text1:default:text word1:default:word]
// k:v pairs for array member: 0
// disable : yes
// text1 : default:text
// word1 : default:word
*/
}
func ExampleMap_UpdateValuesForPath() {
/*
var biblioDoc = []byte(`
<biblio>
<author>
<name>William Gaddis</name>
<books>
<book>
<title>The Recognitions</title>
<date>1955</date>
<review>A novel that changed the face of American literature.</review>
</book>
<book>
<title>JR</title>
<date>1975</date>
<review>Winner of National Book Award for Fiction.</review>
</book>
</books>
</author>
</biblio>`)
...
m, merr := mxj.NewMapXml(biblioDoc)
if merr != nil {
// handle error
}
// change 'review' for a book
count, err := m.UpdateValuesForPath("review:National Book Award winner." "*.*.*.*", "title:JR")
if err != nil {
// handle error
}
...
// change 'date' value from string type to float64 type
// Note: the following is equivalent to m, merr := NewMapXml(biblioDoc, mxj.Cast).
path := m.PathForKeyShortest("date")
v, err := m.ValuesForPath(path)
if err != nil {
// handle error
}
var total int
for _, vv := range v {
oldVal := "date:" + vv.(string)
newVal := "date:" + vv.(string) + ":num"
n, err := m.UpdateValuesForPath(newVal, path, oldVal)
if err != nil {
// handle error
}
total += n
}
...
*/
}
func ExampleMap_Copy() {
/*
// Hand-crafted Map values that include structures do NOT Copy() as expected,
// since to simulate a deep copy the original Map value is JSON encoded then decoded.
type str struct {
IntVal int `json:"int"`
StrVal string `json:"str"`
FloatVal float64 `json:"float"`
BoolVal bool `json:"bool"`
private string
}
s := str{IntVal: 4, StrVal: "now's the time", FloatVal: 3.14159, BoolVal: true, private: "Skies are blue"}
m := make(map[string]interface{}, 0)
m["struct"] = interface{}(s)
m["struct_ptr"] = interface{}(&s)
m["misc"] = interface{}(`Now is the time`)
mv := mxj.Map(m)
cp, _ := mv.Copy()
fmt.Printf("mv:\n%s\n", mv.StringIndent(2))
fmt.Printf("cp:\n%s\n", cp.StringIndent(2))
// NoFail output:
// mv:
// misc : [string] Now is the time
// struct : [mxj_test.str] {IntVal:4 StrVal:now's the time FloatVal:3.14159 BoolVal:true private:Skies are blue}
// struct_ptr : [*mxj_test.str] &{IntVal:4 StrVal:now's the time FloatVal:3.14159 BoolVal:true private:Skies are blue}
// cp:
// misc : [string] Now is the time
// struct :
// bool : [bool] true
// float : [float64] 3.14159
// int : [float64] 4
// str : [string] now's the time
// struct_ptr :
// bool : [bool] true
// float : [float64] 3.14159
// int : [float64] 4
// str : [string] now's the time
//
*/
}