假设我的Go结构定义如下:
type MyType struct {
FieldA string
FieldB string
FIeldC string
}
和对应于它的XML如下所示:
<obj>
<fieldA value="apple"/>
<fieldB value="banana"/>
</obj>
其中FieldA和FieldB是必需的,而FieldC是可选的。如何指定struct标签,以便从&#34;值&#34;中获取字段的值。属性?这样:
FieldA string `xml:"fieldA>value,attr"`
FieldB string `xml:"fieldB>value,attr"`
FieldC string `xml:"fieldC>value,attr,omitempty"`
使用attr标志生成&#34; xml:fieldA&gt;值链无效&#34;而这:
FieldA string `xml:"fieldA"`
FieldB string `xml:"fieldB"`
FieldC string `xml:"fieldC,omitempty"`
不会产生错误,但无法找到字段的值。
答案 0 :(得分:1)
要同时支持XML和JSON,您必须定义一个简单类型并在其上实现xml.Unmarshaler
和xml.Marshaler
接口,这是一个示例:
type Field string
func (f Field) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
v := struct {
Value string `xml:"value,attr"`
}{string(f)}
return e.EncodeElement(v, start)
}
func (f *Field) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var v struct {
Value string `xml:"value,attr"`
}
err := d.DecodeElement(&v, &start)
*f = Field(v.Value)
return err
}
答案 1 :(得分:0)
您无法使用fieldA>value
的形式,因为此&#34;路径&#34;的元素表示元素,而value
不是您案例中的元素。
如果要从子元素的属性中获取值,可以为其创建包装类型。
例如:
type Field struct {
Value string `xml:"value,attr"`
}
使用此MyType
结构:
type MyType struct {
FieldA Field `xml:"fieldA"`
FieldB Field `xml:"fieldB"`
FieldC Field `xml:"fieldC"`
}
测试它:
func main() {
mt := MyType{}
if err := xml.Unmarshal([]byte(src), &mt); err != nil {
panic(err)
}
fmt.Printf("%+v\n", mt)
}
const src = `<obj>
<fieldA value="apple"/>
<fieldB value="banana"/>
</obj>`
输出(在 Go Playground 上试试):
{FieldA:{Value:apple} FieldB:{Value:banana} FieldC:{Value:}}
修改强>
如果要使用一个结构处理XML和JSON,则应在XML中使用元素的内容来保存数据(而不是value
属性),例如:
<obj>
<fieldA>apple</fieldA>
<fieldB>banana</fieldB>
</obj>
以及对此进行建模的结构:
type MyType struct {
FieldA string `xml:"fieldA"`
FieldB string `xml:"fieldB"`
FieldC string `xml:"fieldC"`
}
这个结构可以从JSON解组:
const src2 = `{"fieldA": "apple", "fieldB": "banana"}`
mt = MyType{}
if err := json.Unmarshal([]byte(src2), &mt); err != nil {
panic(err)
}
fmt.Printf("%+v\n", mt)
输出:相同:
{FieldA:apple FieldB:banana FieldC:}
{FieldA:apple FieldB:banana FieldC:}
在 Go Playground 上尝试此变体(使用JSON)。
答案 2 :(得分:0)
您可以通过引入具有Value成员的Field
结构来实现:
type MyType struct {
FieldA Field `xml:"fieldA"`
FieldB Field `xml:"fieldB"`
FIeldC Field `xml:"fieldC"`
}
type Field struct {
Value string `xml:"value,attr"`
}
这应该可以解决问题。这是完整的例子:
package main
import (
"encoding/xml"
"fmt"
"io"
"os"
"strings"
)
type MyType struct {
FieldA Field `xml:"fieldA"`
FieldB Field `xml:"fieldB"`
FieldC Field `xml:"fieldC"`
}
type Field struct {
Value string `xml:"value,attr"`
}
func deserializeMyType(reader io.Reader) (MyType, error) {
myType := MyType{}
decoder := xml.NewDecoder(reader)
err := decoder.Decode(&myType)
if err != nil {
return MyType{}, err
}
return myType, nil
}
func main() {
inputXML := `<obj>
<fieldA value="apple"/>
<fieldB value="banana"/>
</obj>`
xmlReader := strings.NewReader(inputXML)
myType, err := deserializeMyType(xmlReader)
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err.Error())
os.Exit(1)
}
fmt.Fprintf(os.Stdout, "%#v\n", myType)
}
示例XML的输出将是:
main.MyType{FieldA:main.Field{Value:"apple"}, FieldB:main.Field{Value:"banana"}, FieldC:main.Field{Value:""}}
您可以在golang.org/src/encoding/xml/example_test.go的go源中找到其他用于驱动XML属性的示例。