英文:
Golang encoding xml doesn't map empty value to nil
问题
我想将标签中的空值映射为对象中的nil值,例如:
我有以下的XML:
<Address>
<city>city</city>
<streetNumber></streetNumber>
</Address>
我的类型是:
type Address struct{
city string `xml:"city"`
streetNumber *int `xml:"streetNumber"`
}
在这种情况下,streetNumber 是 0,但是当我从 XML 中删除 streetNumber 标签时,值应该是 nil。
是否可能在标签为空时将 streetNumber 标签映射为 nil?
英文:
I would like to map empty value from tag to nill value in my object e.g.
I have this xml
<Address>
<city>city</city>
<streetNumber></streetNumber>
</Address>
a my type is
type Address struct{
city string `xml:"city"`
streetNumber *int `xml:"streetNumber"`
}
and in this case streetNumber is 0 but when I delete tag streetNumber from xml value is nil
Is it possible to map streetNumber tag to nil when it is empty?
答案1
得分: 2
你可能想要考虑将streetNumber
作为自己的类型,并使用自定义编组(marshaling),就像这里使用时间格式进行编组一样:https://www.programming-books.io/essential/go/custom-xml-marshaling-aa8105fe264b4b198647cbc718480ba1
我倾向于使用int + Valid bool的组合,但你也可以使用int指针。
**编辑:**更新以包括marshal/unmarshal的潜在实现。
type Address struct {
City string `xml:"city"`
StreetNumber StreetNumber `xml:"streetNumber"`
}
type StreetNumber struct {
Value int
Valid bool
}
func (s StreetNumber) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
// 如果地址为null/unset/invalid,我们将空字符串序列化为值。
v := ""
if s.Valid {
// 地址有值,所以我们将整数转换为字符串。
v = strconv.Itoa(s.Value)
}
// 将字符串`v`编码为XML元素。
return e.EncodeElement(v, start)
}
func (s *StreetNumber) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// 假设值无效,以便我们可以快速退出。
s.Valid = false
s.Value = 0
var v string
if err := d.DecodeElement(&v, &start); err != nil {
// 如果无法解码原始XML,则转发错误。
return err
}
if v == "" {
// 值为空,但这只是第三个null状态,不是错误。
return nil
}
i, err := strconv.Atoi(v)
if err != nil {
// 元素值不是整数,因此这是一个无效状态--转发错误。
return err
}
// 街道号码是有效的整数。
s.Valid = true
s.Value = i
return nil
}
以上是你要翻译的内容。
英文:
You may want to look at making streetNumber
its own type with custom marshaling like what they're doing here with time format:
https://www.programming-books.io/essential/go/custom-xml-marshaling-aa8105fe264b4b198647cbc718480ba1
I'd lean towards the int + Valid bool combo but you could do an int pointer.
Edit: updated to include a potential implementation of marshal/unmarshal.
type Address struct {
City string `xml:"city"`
StreetNumber StreetNumber `xml:"streetNumber"`
}
type StreetNumber struct {
Value int
Valid bool
}
func (s StreetNumber) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
// If the address is null/unset/invalid, we serialize an empty string as the value.
v := ""
if s.Valid {
// The address has a value so we convert the integer to string.
v = strconv.Itoa(s.Value)
}
// Encode the string `v` to the XML element.
return e.EncodeElement(v, start)
}
func (s *StreetNumber) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// Assume the value is invalid so we can just shortcut out.
s.Valid = false
s.Value = 0;
var v string
if err := d.DecodeElement(&v, &start); err != nil {
// Forward the error if it failed to decode the raw XML
return err
}
if v == "" {
// The value was empty, but this is just the 3rd null state, not an error.
return nil
}
i, err := strconv.Atoi(v)
if err != nil {
// The element value was not an integer so this is an invalid state -- forward the error.
return err
}
// The street number was a valid integer.
s.Valid = true
s.Value = i
return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论