Golang的xml编码不会将空值映射为nil。

huangapple go评论81阅读模式
英文:

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

&lt;Address&gt;
   &lt;city&gt;city&lt;/city&gt;
   &lt;streetNumber&gt;&lt;/streetNumber&gt;
&lt;/Address&gt;

a my type is

type Address struct{
   city string `xml:&quot;city&quot;`
   streetNumber *int `xml:&quot;streetNumber&quot;`
}

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:&quot;city&quot;`
	StreetNumber StreetNumber `xml:&quot;streetNumber&quot;`
}

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 := &quot;&quot;
	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(&amp;v, &amp;start); err != nil {
		// Forward the error if it failed to decode the raw XML
		return err
	}

	if v == &quot;&quot; {
		// 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
}

huangapple
  • 本文由 发表于 2022年5月20日 20:24:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/72318894.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定