如何在 golang 中制作自定义类型(字符串)编组 CDATA 格式?
How to make custom type (string) marshal CDATA format in golang?
微信回复需要这样的格式,CDATA就是解析特殊字符。
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[hello world]]></Content>
</xml>
在使用golang
实现规范的时候,发现xml.Marshal()可以和struct标签xml:",cdata"
一起使用。
定义一个结构来处理,代码如下:
package main
import (
"encoding/xml"
"fmt"
"time"
)
type TextMsg struct {
XMLName xml.Name `xml:"xml"`
ToUserName CDATA
FromUserName CDATA
CreateTime int64
MsgType CDATA
Content CDATA
}
type CDATA struct {
Text string `xml:",cdata"`
}
func main() {
msg := TextMsg{
ToUserName: CDATA{"userId"},
FromUserName: CDATA{"appId"},
CreateTime: time.Now().Unix(),
MsgType: CDATA{"text"},
Content: CDATA{"some message like <hello>"}}
b, _ := xml.MarshalIndent(msg, "", " ")
fmt.Println(string(b))
}
Output results:
<xml>
<ToUserName><![CDATA[userId]]></ToUserName>
<FromUserName><![CDATA[appId]]></FromUserName>
<CreateTime>1485837083</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[some message like <hello>]]></Content>
</xml>
但我觉得还不够完美,变量赋值不如普通字符串类型方便,所以我把CDATA改成字符串类型,尝试实现MarshalXML():
package main
import (
"encoding/xml"
"fmt"
"time"
)
type TextMsg struct {
XMLName xml.Name `xml:"xml"`
ToUserName CDATA
FromUserName CDATA
CreateTime int64
MsgType CDATA
Content CDATA
}
type CDATA string
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
e.EncodeElement("<![CDATA["+string(c)+"]]>", start)
return nil
}
func main() {
msg := TextMsg{
ToUserName: "userId",
FromUserName: "appId",
CreateTime: time.Now().Unix(),
MsgType: "text",
Content: "some message like <hello>"}
b, _ := xml.MarshalIndent(msg, "", " ")
fmt.Println(string(b))
}
But the output results do not meet expectations, "<" or ">" is
escaped:
<xml>
<ToUserName><![CDATA[userId]]></ToUserName>
<FromUserName><![CDATA[appId]]></FromUserName>
<CreateTime>1485837470</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[some message like <hello>]]></Content>
</xml>
有什么好的建议可以给我,谢谢
您可以创建另一个具有标记 xml:",cdata"
的结构 CDATA2
,并将其传递给 EncodeElement()
。
EncodeElement()
会将 CDATA2{"foo<>"}
正确编码为 <![CDATA[foo<>]]>
.
type CDATA2 struct {
Text string `xml:",cdata"`
}
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
e.EncodeElement(CDATA2{string(c)}, start)
return nil
}
编辑:如果不想定义命名类型,可以使用匿名结构
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
e.EncodeElement(struct {
string `xml:",cdata"`
}{string(c)}, start)
return nil
}
微信回复需要这样的格式,CDATA就是解析特殊字符。
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[hello world]]></Content>
</xml>
在使用golang
实现规范的时候,发现xml.Marshal()可以和struct标签xml:",cdata"
一起使用。
定义一个结构来处理,代码如下:
package main
import (
"encoding/xml"
"fmt"
"time"
)
type TextMsg struct {
XMLName xml.Name `xml:"xml"`
ToUserName CDATA
FromUserName CDATA
CreateTime int64
MsgType CDATA
Content CDATA
}
type CDATA struct {
Text string `xml:",cdata"`
}
func main() {
msg := TextMsg{
ToUserName: CDATA{"userId"},
FromUserName: CDATA{"appId"},
CreateTime: time.Now().Unix(),
MsgType: CDATA{"text"},
Content: CDATA{"some message like <hello>"}}
b, _ := xml.MarshalIndent(msg, "", " ")
fmt.Println(string(b))
}
Output results:
<xml>
<ToUserName><![CDATA[userId]]></ToUserName>
<FromUserName><![CDATA[appId]]></FromUserName>
<CreateTime>1485837083</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[some message like <hello>]]></Content>
</xml>
但我觉得还不够完美,变量赋值不如普通字符串类型方便,所以我把CDATA改成字符串类型,尝试实现MarshalXML():
package main
import (
"encoding/xml"
"fmt"
"time"
)
type TextMsg struct {
XMLName xml.Name `xml:"xml"`
ToUserName CDATA
FromUserName CDATA
CreateTime int64
MsgType CDATA
Content CDATA
}
type CDATA string
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
e.EncodeElement("<![CDATA["+string(c)+"]]>", start)
return nil
}
func main() {
msg := TextMsg{
ToUserName: "userId",
FromUserName: "appId",
CreateTime: time.Now().Unix(),
MsgType: "text",
Content: "some message like <hello>"}
b, _ := xml.MarshalIndent(msg, "", " ")
fmt.Println(string(b))
}
But the output results do not meet expectations, "<" or ">" is escaped:
<xml>
<ToUserName><![CDATA[userId]]></ToUserName>
<FromUserName><![CDATA[appId]]></FromUserName>
<CreateTime>1485837470</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[some message like <hello>]]></Content>
</xml>
有什么好的建议可以给我,谢谢
您可以创建另一个具有标记 xml:",cdata"
的结构 CDATA2
,并将其传递给 EncodeElement()
。
EncodeElement()
会将 CDATA2{"foo<>"}
正确编码为 <![CDATA[foo<>]]>
.
type CDATA2 struct {
Text string `xml:",cdata"`
}
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
e.EncodeElement(CDATA2{string(c)}, start)
return nil
}
编辑:如果不想定义命名类型,可以使用匿名结构
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
e.EncodeElement(struct {
string `xml:",cdata"`
}{string(c)}, start)
return nil
}