Source file src/encoding/json/jsontext/example_test.go
1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build goexperiment.jsonv2 6 7 package jsontext_test 8 9 import ( 10 "bytes" 11 "fmt" 12 "io" 13 "log" 14 "strings" 15 16 "encoding/json/jsontext" 17 "encoding/json/v2" 18 ) 19 20 // This example demonstrates the use of the [Encoder] and [Decoder] to 21 // parse and modify JSON without unmarshaling it into a concrete Go type. 22 func Example_stringReplace() { 23 // Example input with non-idiomatic use of "Golang" instead of "Go". 24 const input = `{ 25 "title": "Golang version 1 is released", 26 "author": "Andrew Gerrand", 27 "date": "2012-03-28", 28 "text": "Today marks a major milestone in the development of the Golang programming language.", 29 "otherArticles": [ 30 "Twelve Years of Golang", 31 "The Laws of Reflection", 32 "Learn Golang from your browser" 33 ] 34 }` 35 36 // Using a Decoder and Encoder, we can parse through every token, 37 // check and modify the token if necessary, and 38 // write the token to the output. 39 var replacements []jsontext.Pointer 40 in := strings.NewReader(input) 41 dec := jsontext.NewDecoder(in) 42 out := new(bytes.Buffer) 43 enc := jsontext.NewEncoder(out, jsontext.Multiline(true)) // expand for readability 44 for { 45 // Read a token from the input. 46 tok, err := dec.ReadToken() 47 if err != nil { 48 if err == io.EOF { 49 break 50 } 51 log.Fatal(err) 52 } 53 54 // Check whether the token contains the string "Golang" and 55 // replace each occurrence with "Go" instead. 56 if tok.Kind() == '"' && strings.Contains(tok.String(), "Golang") { 57 replacements = append(replacements, dec.StackPointer()) 58 tok = jsontext.String(strings.ReplaceAll(tok.String(), "Golang", "Go")) 59 } 60 61 // Write the (possibly modified) token to the output. 62 if err := enc.WriteToken(tok); err != nil { 63 log.Fatal(err) 64 } 65 } 66 67 // Print the list of replacements and the adjusted JSON output. 68 if len(replacements) > 0 { 69 fmt.Println(`Replaced "Golang" with "Go" in:`) 70 for _, where := range replacements { 71 fmt.Println("\t" + where) 72 } 73 fmt.Println() 74 } 75 fmt.Println("Result:", out.String()) 76 77 // Output: 78 // Replaced "Golang" with "Go" in: 79 // /title 80 // /text 81 // /otherArticles/0 82 // /otherArticles/2 83 // 84 // Result: { 85 // "title": "Go version 1 is released", 86 // "author": "Andrew Gerrand", 87 // "date": "2012-03-28", 88 // "text": "Today marks a major milestone in the development of the Go programming language.", 89 // "otherArticles": [ 90 // "Twelve Years of Go", 91 // "The Laws of Reflection", 92 // "Learn Go from your browser" 93 // ] 94 // } 95 } 96 97 // Directly embedding JSON within HTML requires special handling for safety. 98 // Escape certain runes to prevent JSON directly treated as HTML 99 // from being able to perform <script> injection. 100 // 101 // This example shows how to obtain equivalent behavior provided by the 102 // v1 [encoding/json] package that is no longer directly supported by this package. 103 // Newly written code that intermix JSON and HTML should instead be using the 104 // [github.com/google/safehtml] module for safety purposes. 105 func ExampleEscapeForHTML() { 106 page := struct { 107 Title string 108 Body string 109 }{ 110 Title: "Example Embedded Javascript", 111 Body: `<script> console.log("Hello, world!"); </script>`, 112 } 113 114 b, err := json.Marshal(&page, 115 // Escape certain runes within a JSON string so that 116 // JSON will be safe to directly embed inside HTML. 117 jsontext.EscapeForHTML(true), 118 jsontext.EscapeForJS(true), 119 jsontext.Multiline(true)) // expand for readability 120 if err != nil { 121 log.Fatal(err) 122 } 123 fmt.Println(string(b)) 124 125 // Output: 126 // { 127 // "Title": "Example Embedded Javascript", 128 // "Body": "\u003cscript\u003e console.log(\"Hello, world!\"); \u003c/script\u003e" 129 // } 130 } 131