首页 > 其他分享 >Golang中如何自定义时间类型进行xml、json的序列化/反序列化

Golang中如何自定义时间类型进行xml、json的序列化/反序列化

时间:2023-12-01 09:46:18浏览次数:42  
标签:xml 自定义 err innerTime XSDDateTime xdt 序列化

在日常开发工作中,我们进行会遇到将 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

标签:xml,自定义,err,innerTime,XSDDateTime,xdt,序列化
From: https://www.cnblogs.com/huageyiyangdewo/p/17868923.html

相关文章

  • XmlRPC入门_组合类型操作
    1、数组操作#include<iostream>#include<winsock2.h>#include<windows.h>#include<xmlrpc-c/base.hpp>#include<xmlrpc-c/registry.hpp>#include<xmlrpc-c/server_abyss.hpp>#include<direct.h>#include<stdio.h&......
  • XmlRPC入门_基本类型操作
    #include<iostream>#include<winsock2.h>#include<windows.h>#include<xmlrpc-c/base.hpp>#include<xmlrpc-c/registry.hpp>#include<xmlrpc-c/server_abyss.hpp>#include<direct.h>#include<stdio.h>#inc......
  • 自定义bib文件
    一、使用在使用word编写论文时,需要使用参考论文格式,此时可以使用bib生成指定的格式,在放入文中进行使用。latex自带了一种bib参考格式的指令:latexmakebst通过上面的指令可以通过选项进行操作生成一个dbj文件。再通过对dbj文件的内容进行修改,就可以到一个目标的bst文件。但是......
  • vue关于自定义指令
    私有自定义指令(在与data()同级结构中进行配置)//私有自定义指令的节点directives:{//定义名为color的指令,指向一个配置对象color:{//当指令第一次被绑到元素上的时候,会立即触发bind函数,只会调用一次//形参中的el表示当前指令所绑定到的那个d......
  • uniapp使用微信jssdk自定义分享
    前言提示:本文记录的是使用uniapp开发的H5+APP项目,H5端使用微信自定义分享功能,文中有关APP的兼容,如果不需要兼容APP的可以忽略一、引入首先安装jweixin-module包npminstalljweixin-module--save二、封装工具方法为了方便使用,新建一个wechat.js文件://#ifdefH5impo......
  • 关于自定义R类-前后端数据交互协议
    关于自定义R类-前后端数据交互协议前言这是我在学习前后端分离开发时遇到的一种前后端数据交互思想时的笔记记录,以便日后遗忘查阅;目录目录关于自定义R类-前后端数据交互协议前言目录一、什么是前后端数据交互协议二、如何自定义一个结果类①思考R类要包含哪些基础属性②设......
  • tita升级|考核流程支持自定义配置
    升级详情:“推荐你关注一下TitaOKR“1.考核流程中新增指标制定与确认流程Q1:在哪新增?小T:在考核模板的考核流程设置中,指标制定与指标确认流程节点有两种添加方式:1)考核模板中新增固定流程三,固定流程三为考核流程为“指标制定+指标确认+执行期+员工自评+同事评价+上级评价+绩效校......
  • XmlRPC入门_形参定义
    形参类型的定义略Thestringlookssomethinglikethisexample:i:iii,s:.Itisalistofsignaturestrings,separatedbycommas.Intheexample,therearetwosignatures:i:iiis:Eachsignaturestringdescribesoneformofcallingthemethod.Asignatures......
  • 使用RabbitMQ时使用MemoryPack序列化和反序列化对象
    [MemoryPackable]publicpartialclassUserEto{publicStringName{get;set;}} 发送端publicclassEventBus:IEventBus{publicvoidPublish(stringexchangeName,objecteventData){usingvarconnection=RabbitMQ......
  • 自定义标签
    1.在应用(如:app01)下创建文件夹templatetags再创建一个py文件,编写自定义标签(如:mytag) 2.编写自定义标签fromdjangoimporttemplateregister=template.Library()@register.filter(name="cut")defcut(value,arg):returnvalue.replace(arg,"")@register.filt......