英文:
Go XML Marshalling and the Root Element
问题
在Go语言中,你可以将一个结构体转换为XML格式,例如:
package main
import (
"encoding/xml"
"fmt"
)
type person struct {
Name string
Starsign string
}
func main() {
p := &person{"John Smith", "Capricorn"}
b, _ := xml.MarshalIndent(p, "", " ")
fmt.Println(string(b))
}
输出结果为:
<person>
<Name>John Smith</Name>
<Starsign>Capricorn</Starsign>
</person>
我的问题是,person类型是小写的“p”,因为我希望它对包私有。但是我更希望XML元素是大写的:“xml:"name"
)来将结构体中的字段转换为其他名称,但是对于结构体类型似乎没有这个选项。
我有一个使用模板的解决方法,但是知道更好的答案会更好。
英文:
In Go, you can marshall a struct to XML, e.g.:
package main
import (
"encoding/xml"
"fmt"
)
type person struct {
Name string
Starsign string
}
func main() {
p := &person{"John Smith", "Capricorn"}
b,_ := xml.MarshalIndent(p,""," ")
fmt.Println(string(b))
}
produces output:
<person>
<Name>John Smith</Name>
<Starsign>Capricorn</Starsign>
</person>
My problem is, the person type is lower-case "p" because I want that to be private to the package. But I'd prefer the XML element to be uppercase: <Person>
. The fields within the struct can be marshalled to other names using tags (e.g. `xml:"name"`) against the structure fields but this doesn't seem to be an option for the structure type.
I have a work-around using templates, but it would be nice to know a better answer.
答案1
得分: 14
根据encoding/xml.Marshal文档:
> XML元素的名称按照以下优先顺序确定:
>- 如果数据是一个结构体,则使用XMLName字段上的标签
- 如果数据是xml.Name类型,则使用XMLName字段的值
- 如果数据是通过结构体字段获取的,则使用该字段的标签
- 如果数据是通过结构体字段获取的,则使用该字段的名称
- 如果数据是通过编组类型获取的,则使用编组类型的名称
您可以在结构体的XMLName字段上使用标签来覆盖person结构体的XML标签名称。为了避免将其放在实际的person结构体中,您可以创建一个嵌入了您正在编组的person结构体的匿名结构体。
package main
import (
"encoding/xml"
"fmt"
)
type person struct {
Name string
Starsign string
}
func marshalPerson(p person) ([]byte, error) {
tmp := struct {
person
XMLName struct{} `xml:"Person"`
}{person: p}
return xml.MarshalIndent(tmp, "", " ")
}
func main() {
p := person{"John Smith", "Capricorn"}
b, _ := marshalPerson(p)
fmt.Println(string(b))
}
英文:
According to the encoding/xml.Marshal documentation:
> The name for the XML elements is taken from, in order of preference:
>- the tag on the XMLName field, if the data is a struct
- the value of the XMLName field of type xml.Name
- the tag of the struct field used to obtain the data
- the name of the struct field used to obtain the data
- the name of the marshalled type
You can use a tag on the XMLName field in the struct to override the person struct's XML tag name. In order to avoid putting it in your actual person struct, you can create an anonymous struct that embeds the person struct you are marshaling.
package main
import (
"encoding/xml"
"fmt"
)
type person struct {
Name string
Starsign string
}
func marshalPerson(p person) ([]byte, error) {
tmp := struct {
person
XMLName struct{} `xml:"Person"`
}{person: p}
return xml.MarshalIndent(tmp, "", " ")
}
func main() {
p := person{"John Smith", "Capricorn"}
b, _ := marshalPerson(p)
fmt.Println(string(b))
}
答案2
得分: 5
这也可以工作,虽然我不认为它特别漂亮。
然而,对我来说,这种方法比5年前的其他解决方案更直接。
package main
import (
"encoding/xml"
"fmt"
)
type person struct {
XMLName xml.Name
Name string
Starsign string
}
func main() {
p := &person{xml.Name{Local: "Person"}, "John Smith", "Capricorn"}
b,_ := xml.MarshalIndent(p,""," ")
fmt.Println(string(b))
}
英文:
This also works, though I don't think it's particularly pretty.
However, this worked in a lot more straight forward manner for me than the other accepted solution from 5 years ago.
package main
import (
"encoding/xml"
"fmt"
)
type person struct {
XMLName xml.Name
Name string
Starsign string
}
func main() {
p := &person{xml.Name{Local: "Person"}, "John Smith", "Capricorn"}
b,_ := xml.MarshalIndent(p,""," ")
fmt.Println(string(b))
}
答案3
得分: 4
我认为最简单的方法就是向person结构体添加一个带有XML标签的虚拟字段。
一个struct{}
元素不使用任何存储空间,我用unsafe.Sizeof()
进行了检查。
package main
import (
"encoding/xml"
"fmt"
)
type person struct {
Name string
Starsign string
XMLName struct{} `xml:"Person"`
}
func main() {
p := &person{Name: "John Smith", Starsign: "Capricorn"}
b, _ := xml.MarshalIndent(p, "", " ")
fmt.Println(string(b))
}
<kbd>go playground</kbd>
如果你喜欢在不使用字段名的情况下初始化结构体,需要添加一个项目来初始化空结构体,像这样:
p := &person{"John Smith", "Capricorn", struct{}{}}
英文:
I think the easiest thing is just to add a dummy field to the person struct with the XML tag.
A struct{}
element does not use any storage, I checked with unsafe.Sizeof()
.
package main
import (
"encoding/xml"
"fmt"
)
type person struct {
Name string
Starsign string
XMLName struct{} `xml:"Person"`
}
func main() {
p := &person{Name: "John Smith", Starsign: "Capricorn"}
b, _ := xml.MarshalIndent(p, "", " ")
fmt.Println(string(b))
}
<kbd>go playground</kbd>
If you prefer to initialize the struct without using field names, it is necessary to add an item to initialize the empty struct, like this:
p := &person{"John Smith", "Capricorn", struct{}{}}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论