英文:
Restructuring xml by using only one struct type for marshal/unmarshal-ing in go
问题
假设你想要使用原始结构体"v"自动进行编组,并使用不同的XML标签,而不是像现在这样分配一个新的结构体类型"newV"并逐个复制字段。这是可能的吗?
不幸的是,Go语言的encoding/xml包不支持直接在编组时更改XML标签。在这种情况下,你需要使用两个不同的结构体类型来表示不同的XML结构,并进行字段复制。
你可以尝试使用反射来自动复制字段,但这可能会导致性能下降,并且代码会更加复杂。因此,目前最简单和可读性最好的方法是创建一个新的结构体类型并手动复制字段。
如果你对性能要求不高,可以尝试使用反射来自动复制字段。以下是一个示例代码:
package main
import (
"encoding/xml"
"fmt"
"os"
"reflect"
)
type Result struct {
Person string `xml:"person>name"`
Id int `xml:"id>number"`
}
type Restructured struct {
Person string
Id int
}
const data = `
<Result>
<person>
<name>Dave</name>
</person>
<id>
<number>1234</number>
</id>
</Result>`
func main() {
v := Result{}
err := xml.Unmarshal([]byte(data), &v)
if err != nil {
fmt.Printf("error: %v", err)
return
}
newV := Restructured{}
copyFields(&newV, &v)
output, err := xml.MarshalIndent(newV, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
}
os.Stdout.Write(output)
}
func copyFields(dest, src interface{}) {
destValue := reflect.ValueOf(dest).Elem()
srcValue := reflect.ValueOf(src).Elem()
for i := 0; i < destValue.NumField(); i++ {
destField := destValue.Field(i)
srcField := srcValue.FieldByName(destValue.Type().Field(i).Name)
if destField.CanSet() && srcField.IsValid() {
destField.Set(srcField)
}
}
}
请注意,使用反射可能会导致性能下降,并且代码会更加复杂。因此,如果性能是一个关键问题,手动复制字段可能是更好的选择。
英文:
Say I have following block of xml data.
<Result>
<person>
<name>Dave</name>
</person>
<id>
<number>1234</number>
</id>
</Result>
and I want to restructure it to following.
<Restructured>
<Person>Dave</Person>
<Id>1234</Id>
</Restructured>
But only using one struct to do it. Is it possible?
Attaching code below.
package main
import (
"encoding/xml"
"fmt"
"os"
)
type Result struct {
Person string `xml:"person>name"`
Id int `xml:"id>number"`
}
type Restructured struct {
Person string
Id int
}
const data = `
<Result>
<person>
<name>Dave</name>
</person>
<id>
<number>1234</number>
</id>
</Result>`
func main() {
v := Result{}
err := xml.Unmarshal([]byte(data), &v)
if err != nil {
fmt.Printf("error: %v", err)
return
}
newV := Restructured{Person: v.Person, Id: v.Id}
output, err := xml.MarshalIndent(newV, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
}
os.Stdout.Write(output)
}
I don't want to do it like this, allocating a new type of struct("newV") and copying field by field.
Is there any way to marshal automatically with different xml tags using original struct "v"?
答案1
得分: 2
使用第二个结构体是我看到的最方便的方法。如果你不想将其导出,实际上可以在MarshalXML
中隐藏另一个类型:
func (r *Result) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
type Restructured struct {
Person string
ID int `xml:"Id"`
}
rr := &Restructured{Person: r.Person, ID: r.ID}
return enc.Encode(rr)
}
Playground: http://play.golang.org/p/jZU2Jg0ZRZ.
英文:
Using a second struct is the most convenient way I see. If you don't want to make it exported, you can actually hide the other type inside your MarshalXML
:
func (r *Result) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
type Restructured struct {
Person string
ID int `xml:"Id"`
}
rr := &Restructured{Person: r.Person, ID: r.ID}
return enc.Encode(rr)
}
Playground: http://play.golang.org/p/jZU2Jg0ZRZ.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论