如何阻止json.Marshal转义<和>字符?

huangapple go评论68阅读模式
英文:

How to stop json.Marshal from escaping < and >?

问题

package main

import "fmt"
import "encoding/json"

type Track struct {
XmlRequest string json:"xmlRequest"
}

func main() {
message := new(Track)
message.XmlRequest = "XML"
fmt.Println("Before Marshal", message)
messageJSON, _ := json.Marshal(message)
fmt.Println("After marshal", string(messageJSON))
}

有可能使json.Marshal不转义&lt;&gt;吗?我目前得到的结果是:

{"xmlRequest":"\u003ccar\u003e\u003cmirror\u003eXML\u003c/mirror\u003e\u003c/car\u003e"}

但我希望得到这样的结果:

{"xmlRequest":"<car><mirror>XML</mirror></car>"}

英文:
package main

import &quot;fmt&quot;
import &quot;encoding/json&quot;

type Track struct {
    XmlRequest string `json:&quot;xmlRequest&quot;`
}

func main() {
    message := new(Track)
    message.XmlRequest = &quot;&lt;car&gt;&lt;mirror&gt;XML&lt;/mirror&gt;&lt;/car&gt;&quot;
    fmt.Println(&quot;Before Marshal&quot;, message)
    messageJSON, _ := json.Marshal(message)
    fmt.Println(&quot;After marshal&quot;, string(messageJSON))
}

Is it possible to make json.Marshal not escape &lt; and &gt;? I currently get:

{&quot;xmlRequest&quot;:&quot;\u003ccar\u003e\u003cmirror\u003eXML\u003c/mirror\u003e\u003c/car\u003e&quot;}

but I am looking for something like this:

{&quot;xmlRequest&quot;:&quot;&lt;car&gt;&lt;mirror&gt;XML&lt;/mirror&gt;&lt;/car&gt;&quot;}

答案1

得分: 78

截至Go 1.7版本,你仍然**无法使用json.Marshal()**来实现这个功能。json.Marshal的源代码显示:

> err := e.marshal(v, encOpts{escapeHTML: true})

json.Marshal总是这样做的原因是:

字符串值被编码为强制转换为有效UTF-8的JSON字符串,将无效字节替换为Unicode替换符。角括号“<”和“>”被转义为“\u003c”和“\u003e”,以防止某些浏览器将JSON输出错误地解释为HTML。与此相同的原因,和号“&”也被转义为“\u0026”。

这意味着即使通过编写自定义的func (t *Track) MarshalJSON()也无法实现,你必须使用不满足json.Marshaler接口的其他方法。

因此,解决方法是编写自己的函数:

func (t *Track) JSON() ([]byte, error) {
    buffer := &bytes.Buffer{}
    encoder := json.NewEncoder(buffer)
    encoder.SetEscapeHTML(false)
    err := encoder.Encode(t)
    return buffer.Bytes(), err
}

https://play.golang.org/p/FAH-XS-QMC

如果你想要一个适用于任何结构体的通用解决方案,可以这样做:

func JSONMarshal(t interface{}) ([]byte, error) {
    buffer := &bytes.Buffer{}
    encoder := json.NewEncoder(buffer)
    encoder.SetEscapeHTML(false)
    err := encoder.Encode(t)
    return buffer.Bytes(), err
}

https://play.golang.org/p/bdqv3TUGr3

英文:

As of Go 1.7, you still cannot do this with json.Marshal(). The source code for json.Marshal shows:

&gt; err := e.marshal(v, encOpts{escapeHTML: true})

The reason json.Marshal always does this is:

> String values encode as JSON strings coerced to valid UTF-8,
replacing invalid bytes with the Unicode replacement rune.
The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
to keep some browsers from misinterpreting JSON output as HTML.
Ampersand "&" is also escaped to "\u0026" for the same reason.

This means you cannot even do it by writing a custom func (t *Track) MarshalJSON(), you have to use something that does not satisfy the json.Marshaler interface.

So, the workaround, is to write your own function:

func (t *Track) JSON() ([]byte, error) {
    buffer := &amp;bytes.Buffer{}
    encoder := json.NewEncoder(buffer)
    encoder.SetEscapeHTML(false)
    err := encoder.Encode(t)
    return buffer.Bytes(), err
}

https://play.golang.org/p/FAH-XS-QMC

If you want a generic solution for any struct, you could do:

func JSONMarshal(t interface{}) ([]byte, error) {
    buffer := &amp;bytes.Buffer{}
    encoder := json.NewEncoder(buffer)
    encoder.SetEscapeHTML(false)
    err := encoder.Encode(t)
    return buffer.Bytes(), err
}

https://play.golang.org/p/bdqv3TUGr3

答案2

得分: 36

在Go1.7中,添加了一个新选项来解决这个问题:
> encoding/json:
> 添加了Encoder.DisableHTMLEscaping。这提供了一种在JSON字符串中禁用<、>和&转义的方法。

相关的函数是

func (*Encoder) SetEscapeHTML

应该应用于Encoder

enc := json.NewEncoder(os.Stdout)
enc.SetEscapeHTML(false)

简单示例:https://play.golang.org/p/SJM3KLkYW-

英文:

In Go1.7 the have added a new option to fix this:
> encoding/json:
> add Encoder.DisableHTMLEscaping This provides a way to disable the escaping of <, >, and & in JSON strings.

The relevant function is

func (*Encoder) SetEscapeHTML

That should be applied to a Encoder.

enc := json.NewEncoder(os.Stdout)
enc.SetEscapeHTML(false)

Simple example: https://play.golang.org/p/SJM3KLkYW-

答案3

得分: 8

这不是直接回答问题,但如果你想知道如何处理json.Marshal转义的&lt;&gt;,这可能是一个答案...

解决这个问题的另一种方法是在json.Marshal()调用之后,将json.RawMessage中的转义字符替换为有效的UTF-8字符。

对于除了&lt;&gt;之外的任何字符,这种方法也适用。(我曾经这样做,使非英文字符在JSON中可读:D)

func _UnescapeUnicodeCharactersInJSON(_jsonRaw json.RawMessage) (json.RawMessage, error) {
    str, err := strconv.Unquote(strings.Replace(strconv.Quote(string(_jsonRaw)), `\\u`, `\u`, -1))
    if err != nil {
        return nil, err
    }
    return []byte(str), nil
}

func main() {
    // 两者都是有效的JSON。
    var jsonRawEscaped json.RawMessage   // 带有转义Unicode字符的原始JSON
    var jsonRawUnescaped json.RawMessage // 不带转义Unicode字符的原始JSON

    // '\u263a' == '☺'
    jsonRawEscaped = []byte(`{"HelloWorld": "\uC548\uB155, \uC138\uC0C1(\u4E16\u4E0A). \u263a"}`) // "\\u263a"
    jsonRawUnescaped, _ = _UnescapeUnicodeCharactersInJSON(jsonRawEscaped)                        // "☺"

    fmt.Println(string(jsonRawEscaped))   // {"HelloWorld": "\uC548\uB155, \uC138\uC0C1(\u4E16\u4E0A). \u263a"}
    fmt.Println(string(jsonRawUnescaped)) // {"HelloWorld": "안녕, 세상(世上). ☺"}
}

希望对某人有所帮助。

英文:

This doesn't answer the question directly but it could be an answer if you're looking for a way how to deal with json.Marshal escaping &lt; and &gt;...

Another way to solve the problem is to replace those escaped characters in json.RawMessage into just valid UTF-8 characters, after the json.Marshal() call.

It will work as well for any letters other than &lt; and &gt;. (I used to do this to make non-English letters to be human readable in JSON :D)

func _UnescapeUnicodeCharactersInJSON(_jsonRaw json.RawMessage) (json.RawMessage, error) {
    str, err := strconv.Unquote(strings.Replace(strconv.Quote(string(_jsonRaw)), `\\u`, `\u`, -1))
    if err != nil {
        return nil, err
    }
    return []byte(str), nil
}

func main() {
    // Both are valid JSON.
    var jsonRawEscaped json.RawMessage   // json raw with escaped unicode chars
    var jsonRawUnescaped json.RawMessage // json raw with unescaped unicode chars

    // &#39;\u263a&#39; == &#39;☺&#39;
    jsonRawEscaped = []byte(`{&quot;HelloWorld&quot;: &quot;\uC548\uB155, \uC138\uC0C1(\u4E16\u4E0A). \u263a&quot;}`) // &quot;\\u263a&quot;
    jsonRawUnescaped, _ = _UnescapeUnicodeCharactersInJSON(jsonRawEscaped)                        // &quot;☺&quot;

    fmt.Println(string(jsonRawEscaped))   // {&quot;HelloWorld&quot;: &quot;\uC548\uB155, \uC138\uC0C1(\u4E16\u4E0A). \u263a&quot;}
    fmt.Println(string(jsonRawUnescaped)) // {&quot;HelloWorld&quot;: &quot;안녕, 세상(世上). ☺&quot;}
}

https://play.golang.org/p/pUsrzrrcDG-

I hope this helps someone.

答案4

得分: 6

这是我的解决方法:

// Marshal是一个UTF-8友好的编组器。Go的json.Marshal不是UTF-8友好的,因为它将有效的UTF-8和JSON字符"&"、"<"、">"替换为"slash u" unicode转义形式(例如\u0026)。它预先转义以适应HTML友好性。在文本中可能包含任何这些字符的情况下,不应使用json.Marshal。Go Playground中破坏标题的示例:https://play.golang.org/p/o2hiX0c62oN
func Marshal(i interface{}) ([]byte, error) {
	buffer := &bytes.Buffer{}
	encoder := json.NewEncoder(buffer)
	encoder.SetEscapeHTML(false)
	err := encoder.Encode(i)
	return bytes.TrimRight(buffer.Bytes(), "\n"), err
}
英文:

Here's my workaround:

// Marshal is a UTF-8 friendly marshaler.  Go&#39;s json.Marshal is not UTF-8
// friendly because it replaces the valid UTF-8 and JSON characters &quot;&amp;&quot;. &quot;&lt;&quot;,
// &quot;&gt;&quot; with the &quot;slash u&quot; unicode escaped forms (e.g. \u0026).  It preemptively
// escapes for HTML friendliness.  Where text may include any of these
// characters, json.Marshal should not be used. Playground of Go breaking a
// title: https://play.golang.org/p/o2hiX0c62oN
func Marshal(i interface{}) ([]byte, error) {
	buffer := &amp;bytes.Buffer{}
	encoder := json.NewEncoder(buffer)
	encoder.SetEscapeHTML(false)
	err := encoder.Encode(i)
	return bytes.TrimRight(buffer.Bytes(), &quot;\n&quot;), err
}

答案5

得分: 1

不,你不能。

第三方的json包可能是一个选择,而不是标准的json库。

更多详情请参考:https://github.com/golang/go/issues/8592

英文:

No, you can't.

A third-party json package might be the choice rather than the std json lib.

More detail:https://github.com/golang/go/issues/8592

答案6

得分: 1

我有一个要求,需要将XML存储在JSON中。起初,我在通过JSON传递后解组XML时遇到了很大的困难,但实际上问题是因为我尝试将XML字符串解组为json.RawMessage导致的。实际上,我需要将其解组为字符串,然后将其强制转换为[]byte以供xml.Unmarshal使用。

type xmlInJson struct {
  Data string `json:"data"`
}

var response xmlInJson
err := json.Unmarshal(xmlJsonData, &response)
var xmlData someOtherStructThatMatchesTheXmlFormat
err = xml.Unmarshal([]byte(response.Data), &xmlData)
英文:

I had a requirement to store xml inside json :puke:

At first I was having significant difficulty unmarshalling that xml after passing it via json, but my issue was actually due to trying to unmarshall the xml string as a json.RawMessage. I actually needed to unmarshall it as a string and then coerce it into []byte for the xml.Unmarshal.

type xmlInJson struct {
  Data string `json:&quot;data&quot;`
}

var response xmlInJson
err := json.Unmarshall(xmlJsonData, &amp;response)
var xmlData someOtherStructThatMatchesTheXmlFormat
err = xml.Unmarshall([]byte(response.Data), &amp;xmlData) 

答案7

得分: -2

自定义函数并不是最好的解决方案。

那么使用另一个库来解决如何呢?我使用了gabs库。

导入:

go get "github.com/Jeffail/gabs"

使用:

message := new(Track)
resultJson,_:=gabs.Consume(message)

fmt.Println(string(resultJson.EncodeJSON()))

我是这样解决这个问题的。

英文:

Custom function is not kind of the best solution.

How about another library to solve this.
I use gabs

import

go get &quot;github.com/Jeffail/gabs&quot;

use

message := new(Track)
resultJson,_:=gabs.Consume(message)

fmt.Println(string(resultJson.EncodeJSON()))

I solve that problem like this.

huangapple
  • 本文由 发表于 2015年2月19日 07:04:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/28595664.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定