英文:
`,omitempty` and pointer fields in Go's standard `xml` package
问题
当将结构体的布尔字段编组为XML时,omitempty
选项对大多数情况来说并不是很有用——在Go语言中,false
是布尔变量的零值,因此在编组时,值为false
的布尔字段会被忽略掉。最常建议的解决方案似乎是使用指针,这样可以指示值是否存在。以下是我对这个想法的基本实现:
package main
import (
"encoding/xml"
"fmt"
)
type Person struct {
XMLName xml.Name `xml:"person"`
IsMarried *bool `xml:"married"` // 必需字段。
IsRetired *bool `xml:"retired,omitempty"` // 可选字段。
}
func boolPointer(b bool) *bool {
return &b
}
func printPersonXml(person Person) {
output, err := xml.MarshalIndent(person, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
} else {
fmt.Println(string(output))
}
}
func main() {
person := Person{
IsMarried: boolPointer(true),
IsRetired: nil,
}
printPersonXml(person)
}
这将按预期工作并产生以下输出:
<person>
<married>true</married>
</person>
然而,似乎在这种情况下,omitempty
选项完全失去了意义。任何具有nil
值的字段都不会包含在生成的XML代码中。例如,如果我将main()
的内容更改为:
person := Person{
IsMarried: nil,
IsRetired: nil,
}
printPersonXml(person)
输出将变为:
<person></person>
尽管如此,我更希望输出为:
<person>
<married></married>
</person>
正如这里所指出的,这可能是预期的行为:“Marshal通过编组指针指向的值,或者如果指针为nil,则不写入任何内容。”
然而,是否可能使用标准的xml
包来实现我期望的行为呢?如果可以,是否需要引入新类型和自定义的MarshalXML()
方法呢?
尽管在这里我专注于布尔变量,但我也希望将这种方法扩展到其他基本类型的指针上。
英文:
When marshalling a boolean field of a struct to XML, the ,omitempty
option is not very useful for most purposes—false
is a zero value of boolean variables in Go and, as expected, boolean ,omitempty
fields with value of false are ignored when marshalling. The most often suggested solution seems to be using pointers which would allow to indicate whether a value is present at all. Here is my basic implementation of this idea:
package main
import (
"encoding/xml"
"fmt"
)
type Person struct {
XMLName xml.Name `xml:"person"`
IsMarried *bool `xml:"married"` // Required field.
IsRetired *bool `xml:"retired,omitempty"` // Optional field.
}
func boolPointer(b bool) *bool {
return &b
}
func printPersonXml(person Person) {
output, err := xml.MarshalIndent(person, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
} else {
fmt.Println(string(output))
}
}
func main() {
person := Person{
IsMarried: boolPointer(true),
IsRetired: nil,
}
printPersonXml(person)
}
This works as expected and produces the output
<person>
<married>true</married>
</person>
However, it seems that in this case ,omitempty
option loses its meaning entirely. Any field with nil
value will not be included in the produced XML code. For example, if I change the contents of main()
to
person := Person{
IsMarried: nil,
IsRetired: nil,
}
printPersonXml(person)
the output becomes
<person></person>
even though I would prefer
<person>
<married></married>
</person>
As noted here, this is probably the expected behaviour: "Marshal handles a pointer by marshaling the value it points at or, if the pointer is nil, by writing nothing."
However, is it possible to achieve my preferred behaviour using standard xml
package? If yes, would that require introducing a new type and a custom MarshalXML()
method for it?
Although here I focus on boolean variables for obvious reasons, I would like to extend this approach to pointers of other basic types as well.
答案1
得分: 3
“使用标准的xml包能否实现我期望的行为?如果可以,是否需要引入新的类型和自定义的MarshalXML()方法?” - 是的,可以实现,并且需要引入新的类型和自定义的MarshalXML()方法。
例如:
type Bool struct {
Bool bool
IsValid bool
}
func (b Bool) MarshalXML(e *xml.Encoder, se xml.StartElement) error {
if b.IsValid {
return e.EncodeElement(b.Bool, se)
}
return e.EncodeElement("", se)
}
type OptionalBool struct {
Bool bool
IsValid bool
}
func (b OptionalBool) MarshalXML(e *xml.Encoder, se xml.StartElement) error {
if b.IsValid {
return e.EncodeElement(b.Bool, se)
}
return nil
}
https://play.golang.org/p/C2fuBfv69Ny
英文:
"is it possible to achieve my preferred behaviour using standard xml package? If yes, would that require introducing a new type and a custom MarshalXML() method for it?" -- Yes, and yes.
For example:
type Bool struct {
Bool bool
IsValid bool
}
func (b Bool) MarshalXML(e *xml.Encoder, se xml.StartElement) error {
if b.IsValid {
return e.EncodeElement(b.Bool, se)
}
return e.EncodeElement("", se)
}
type OptionalBool struct {
Bool bool
IsValid bool
}
func (b OptionalBool) MarshalXML(e *xml.Encoder, se xml.StartElement) error {
if b.IsValid {
return e.EncodeElement(b.Bool, se)
}
return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论