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