Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encoding/json: disable HTML escaping and omit final newline #43961

Open
89z opened this issue Jan 27, 2021 · 6 comments
Open

encoding/json: disable HTML escaping and omit final newline #43961

89z opened this issue Jan 27, 2021 · 6 comments
Labels

Comments

@89z
Copy link

@89z 89z commented Jan 27, 2021

I am encoding some JSON. I need to disable HTML escaping, and I need no trailing
newline. It seems no easy way to do this.

If I try json#Marshal, it does HTML escaping with no option to change. If I
try json#Encoder.Encode, it adds newline with no option to change. I came up
with this as a workaround:

package main

import (
   "bytes"
   "encoding/json"
   "fmt"
   "log"
)

func compact(dst *bytes.Buffer, v interface{}) error {
   var src bytes.Buffer
   enc := json.NewEncoder(&src)
   enc.SetEscapeHTML(false)
   err := enc.Encode(v)
   if err != nil {
      return err
   }
   return json.Compact(dst, src.Bytes())
}

func main() {
   var dst bytes.Buffer
   e := compact(&dst, []string{"May", "June & July"})
   if e != nil {
      log.Fatal(e)
   }
   fmt.Printf("%q", dst.String())
}

but its pretty awkward. Also if you wanted to indent, it is difficult, since you
are now calling json#Compact, using json#Encoder.SetIndent would be pointless, you
would have to call json#Indent after everything is done.

https://golang.org/pkg/encoding/json

@seankhliao
Copy link
Contributor

@seankhliao seankhliao commented Jan 28, 2021

This is possible with the current api (as you've demonstrated), see
https://golang.org/doc/faq#x_in_std

@seankhliao seankhliao changed the title JSON: disable HTML escaping and omit final newline encoding/json: disable HTML escaping and omit final newline Jan 28, 2021
@89z
Copy link
Author

@89z 89z commented Jan 28, 2021

@seankhliao my workaround is really inefficient. The Compact function is overkill to essentially remove a trailing newline, when it would be better if option to just not add the newline in the first place.

Also that link doesnt really relate to this issue. Im not asking to add a new package.

@seankhliao
Copy link
Contributor

@seankhliao seankhliao commented Jan 28, 2021

You can just slice off the last element of the byte slice.

@89z
Copy link
Author

@89z 89z commented Jan 28, 2021

Here is another approach, based on your suggestion:

func marshal(v interface{}) ([]byte, error) {
   var dst bytes.Buffer
   enc := json.NewEncoder(&dst)
   enc.SetEscapeHTML(false)
   err := enc.Encode(v)
   if err != nil {
      return nil, err
   }
   return dst.Bytes()[:dst.Len() - 1], nil
}

Although since bytes is already being used, bytes#TrimSpace could be used instead. Here is a similar example using strings instead:

var buf bytes.Buffer
enc := NewEncoder(&buf)
if err := enc.Encode(tt.v); err != nil {
t.Errorf("Encode(%s): %s", tt.name, err)
continue
}
if got := strings.TrimSpace(buf.String()); got != tt.wantEscape {

@mvdan
Copy link
Member

@mvdan mvdan commented Jan 29, 2021

Encoder enforcing a newline is unfortunate, but I agree with @seankhliao that it seems like a very minor inconvenience that doesn't warrant new API.

We are aware that Marshal and Encode are weird APIs, but they are not APIs we can break. And extending Encoder with more options isn't going to be particularly better in the long run :)

@mvdan
Copy link
Member

@mvdan mvdan commented Jan 29, 2021

cc @dsnet

@mvdan mvdan added the NeedsDecision label Jan 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants