Golang中如何自定义时间类型进行xml、json的序列化/反序列化
在日常开发工作中,我们进行会遇到将 struct
序列化 json字符串
以及将 json字符串
反序列化为 struct
的场景,大家也对此十分熟悉。
最近工作中,遇到了需要将 struct
序列化 xml字符串
以及将 xml字符串
反序列化为 struct
的场景,对于普通类型的字段,比如int、string
等类型,直接使用并没有啥问题。
当遇到 时间类型
时,序列化和反序列化并不是自己想要的格式,这个时候就需要我们自定义时间类型的序列化/反序列化方式。
对于json
序列化时间类型
,大家可能已经比较熟悉了,一般是自定义一个时间类型或者为struct自定义MarshalJSON()([]byte, error)
和UnmarshalJSON(b []byte) error
方法,这样就可以实现将时间格式化为我们想要的格式了。
其实对于xml
来说也是一样的,方式也是上面两种,这里就介绍下自定义时间类型,来实现xml的序列化/反序列化。
代码如下:
package main
import (
"encoding/json"
"encoding/xml"
"fmt"
"strings"
"time"
)
const timeLayout = "2006-01-02T15:04:05.000+08:00"
var location *time.Location
func init() {
location, _ = time.LoadLocation("Asia/Shanghai")
}
// XSDDateTime is a type for representing xsd:datetime in Golang
type 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 used
func (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 CST
2023-11-30T11:00:54.091+08:00