2017-01-31 5 views
0

WeChatメッセージの返信にはこのような形式が必要です.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

タグ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 
} 

でそれを確認してください:Go Playground

編集Go Playground

+0

:あなたが名前付きの型を定義したくない場合は、

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

はそれをチェックし、匿名構造体を使用することができます本当に良いアイデアです。コードを変更して、余分な構造体がエクスポートされないようにしました: 'func(c CDATA)Mar shalXMLエラー{ \tリターンe.EncodeElement(E * xml.Encoder、xml.StartElement開始)(構造体を{ \t \t文字列 "XML:\"、CDATAの\ "" \t} {(C)}は、開始文字列) } ' – woylyn

+0

@woylynよろしくお願いします。あなたのコードははるかに賢いようです。私は答えを編集するだろう。 – ymonad

関連する問題