在日常开发工作中,我们进行会遇到将 struct 序列化 json字符串以及将 json字符串 反序列化为 struct 的场景,大家也对此十分熟悉。
最近工作中,遇到了需要将 struct 序列化 xml字符串以及将 xml字符串 反序列化为 struct 的场景,对于普通类型的字段,比如int、string 等类型,直接使用并没有啥问题。
当遇到 时间类型 时,序列化和反序列化并不是自己想要的格式,这个时候就需要我们自定义时间类型的序列化/反序列化方式。
对于json序列化时间类型,大家可能已经比较熟悉了,一般是自定义一个时间类型或者为struct自定义MarshalJSON()([]byte, error)和UnmarshalJSON(b []byte) error方法,这样就可以实现将时间格式化为我们想要的格式了。
其实对于xml来说也是一样的,方式也是上面两种,这里就介绍下自定义时间类型,来实现xml的序列化/反序列化。
代码如下:
package mainimport ( "encoding/json" "encoding/xml" "fmt" "strings" "time")const timeLayout = "2006-01-02T15:04:05.000+08:00"var location *time.Locationfunc init() { location, _ = time.LoadLocation("Asia/Shanghai")}// XSDDateTime is a type for representing xsd:datetime in Golangtype XSDDateTime struct { innerTime time.Time}func CreateXSDDateTime(dt time.Time) XSDDateTime { return XSDDateTime{ innerTime: dt, }}func (xdt XSDDateTime) String() string { return xdt.innerTime.Format(timeLayout)}// ToGoTime converts the time to time.Time by checking if a TZ is specified.// If there is a TZ, that TZ is used, otherwise local TZ is usedfunc (xdt *XSDDateTime) ToGoTime() time.Time { return time.Date(xdt.innerTime.Year(), xdt.innerTime.Month(), xdt.innerTime.Day(), xdt.innerTime.Hour(), xdt.innerTime.Minute(), xdt.innerTime.Second(), xdt.innerTime.Nanosecond(), location)}func (xdt XSDDateTime) MarshalXMLAttr(name xml.Name) (xml.Attr, error) { value := xdt.innerTime.Format(timeLayout) attr := xml.Attr{Name: name, Value: value} return attr, nil}func (xdt *XSDDateTime) UnmarshalXMLAttr(attr xml.Attr) error { value := attr.Value t, err := time.Parse(timeLayout, value) if err != nil { return err } xdt.innerTime = t return nil}func (xdt XSDDateTime) MarshalXML(e *xml.Encoder, start xml.StartElement) error { formatted := xdt.innerTime.Format(timeLayout) return e.EncodeElement(formatted, start)}func (xdt *XSDDateTime) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { var value string if err := d.DecodeElement(&value, &start); err != nil { return err } parsedTime, err := time.Parse(timeLayout, value) if err != nil { return err } xdt.innerTime = parsedTime return nil}func (xdt XSDDateTime) MarshalJSON() ([]byte, error) { return []byte(fmt.Sprintf(`"%s"`, xdt.innerTime.Format(timeLayout))), nil}func (xdt *XSDDateTime) UnmarshalJSON(data []byte) error { var dt time.Time if err := json.Unmarshal(data, &dt); err != nil { return err } xdt.innerTime = dt return nil}type Test struct { TD XSDDateTime `xml:"TD,attr"` TD1 *XSDDateTime `xml:"TD1,attr,omitempty"` T XSDDateTime `xml:"T"` T1 *XSDDateTime `xml:"T1,omitempty"`}func main() { // 创建一个 soap.XSDDateTime 类型的实例 xsdDateTime := CreateXSDDateTime(time.Now()) fmt.Println("now -->", time.Now()) t := Test{ TD: xsdDateTime, T: xsdDateTime, } // 使用 xml.Marshal 将 soap.XSDDateTime 编组为 XML 数据 xmlData, err := xml.MarshalIndent(t, "", " ") if err != nil { fmt.Println("Error marshaling:", err) return } // 输出编组后的 XML 数据 fmt.Println(string(xmlData)) fmt.Println(strings.Repeat("-", 10)) //tt := `<Test TD="2023-11-24T10:24:27.129+08:00"> //<T>2023-11-24T18:22:27.129+08:00</T> //</Test> //` tt := string(xmlData) var dddd Test err = xml.Unmarshal([]byte(tt), &dddd) fmt.Println(err) fmt.Printf("Test --> %+v\n", dddd) fmt.Printf("%v\n", dddd.T.ToGoTime()) fmt.Printf("%v\n", dddd.T.ToGoTime().Format(timeLayout))}
执行结果:
now --> 2023-11-30 11:00:54.0918059 +0800 CST m=+0.003982301<Test TD="2023-11-30T11:00:54.091+08:00"> <T>2023-11-30T11:00:54.091+08:00</T></Test>----------<nil>t --> {TD:2023-11-30T11:00:54.091+08:00 TD1:<nil> T:2023-11-30T11:00:54.091+08:00 T1:<nil>}2023-11-30 11:00:54.091 +0800 CST2023-11-30T11:00:54.091+08:00