dream5694 2017-01-31 06:52
浏览 111
已采纳

如何在Golang中创建自定义类型(字符串)的元数据CDATA格式?

WeChat message reply requires such a format, CDATA is to resolve the special characters.

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[hello world]]></Content>
</xml>

When using golang to achieve the specification,I found that the xml.Marshal () can be used with the struct tag xml:",cdata" . Define a struct to deal with, the codes seems like:

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>

But I think it's not perfect, since variable assignment is not as convenient as the normal string type, so I change the CDATA into string type, and try to achieve 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>&lt;![CDATA[userId]]&gt;</ToUserName>
    <FromUserName>&lt;![CDATA[appId]]&gt;</FromUserName>
    <CreateTime>1485837470</CreateTime>
    <MsgType>&lt;![CDATA[text]]&gt;</MsgType>
    <Content>&lt;![CDATA[some message like &lt;hello&gt;]]&gt;</Content>
</xml>

Do you have any good suggestions for me, thank you.

  • 写回答

1条回答 默认 最新

  • duanji5569 2017-01-31 08:02
    关注

    You can create another structure CDATA2 which has tag xml:",cdata", and pass it to EncodeElement().

    EncodeElement() would correctly encode CDATA2{"foo<>"} to <![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
    }
    

    Check it in: Go Playground

    Edit: you can use anonymous struct if you don't want to define named type

    func (c CDATA) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
        e.EncodeElement(struct {
            string `xml:",cdata"`
        }{string(c)}, start)
        return nil
    }
    

    Check it in: Go Playground

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题
  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度
  • ¥15 c# 使用NPOI快速将datatable数据导入excel中指定sheet,要求快速高效
  • ¥15 再不同版本的系统上,TCP传输速度不一致
  • ¥15 高德地图2.0 版本点聚合中Marker的位置无法实时更新,如何解决呢?
  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题