如何在golang中自定义类型(字符串)元帅CDATA格式?
问题描述:
微信息回复需要这样的格式,CDATA是解析特殊字符。如何在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()可以与结构标签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))
}
输出结果:
<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))
}
但输出结果不符合预期,“<”或“>”是 转义:
<xml>
<ToUserName><![CDATA[userId]]></ToUserName>
<FromUserName><![CDATA[appId]]></FromUserName>
<CreateTime>1485837470</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[some message like <hello>]]></Content>
</xml>
你对我有什么好的建议,谢谢。
答
您可以创建另一个结构CDATA2
其标签xml:",cdata"
,并将其传递给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
}
检查它在:Go Playground
编辑:您可以使用匿名结构,如果你不希望定义一个名为类型
func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
e.EncodeElement(struct {
string `xml:",cdata"`
}{string(c)}, start)
return nil
}
检查它在:Go Playground
非常感谢!这真是一个好主意。我更改了代码,以便不会导出额外的结构:'func(c CDATA)Mar shalXML(E * xml.Encoder,启动xml.StartElement)错误{ \t返回e.EncodeElement(结构{ \t \t字符串 “XML:\”,CDATA \ “” \t} {串(C)},启动) }' – woylyn
@woylyn不客气。因为你的代码看起来更聪明。我会编辑答案。 – ymonad