2017-01-31 33 views
0

微信息回覆需要這樣的格式,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>&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> 

你對我有什麼好的建議,謝謝。

回答

0

您可以創建另一個結構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

+0

非常感謝!這真是一個好主意。我更改了代碼,以便不會導出額外的結構:'func(c CDATA)Mar shalXML(E * xml.Encoder,啓動xml.StartElement)錯誤{ \t返回e.EncodeElement(結構{ \t \t字符串 「XML:\」,CDATA \ 「」 \t} {串(C)},啓動) }' – woylyn

+0

@woylyn不客氣。因爲你的代碼看起來更聰明。我會編輯答案。 – ymonad