尝试使用类型为map [string] interface {}的字段构造xml.Unmarshal时出错

时间:2015-07-01 09:00:31

标签: go

问题是带有map [string] interface {}类型字段的struct的xml.Unmarshal将失败并显示错误:

unknown type map[string]interface {}
{XMLName:{Space: Local:myStruct} Name:test Meta:map[]}

由于类型map [string] interface {}的元字段是我可以定义的,所以内部必须动态解组。

package main

import (
    "encoding/xml"
    "fmt"
)

func main() {
    var myStruct MyStruct

    // meta is as far as we know, inside meta, dynamic properties and nesting will happen
    s := `<myStruct>
        <name>test</name>
        <meta>
            <someProp>something</someProp>
            <someOtherDynamic>
                <name>test</name>
                <somethingElse>test2</somethingElse>
                <nested3>
                    <name>nested3</name>
                    <nested3elements>
                        <elem>ele1</elem>
                        <elem>ele2</elem>
                    </nested3elements>
                </nested3>
            </someOtherDynamic>
        </meta>
    </myStruct>`

    err := xml.Unmarshal([]byte(s), &myStruct)
    if err == nil {
        fmt.Printf("%+v\n", myStruct)
    } else {
        fmt.Println(err)
        fmt.Printf("%+v\n", myStruct)
    }
}

type MyStruct struct {
    XMLName xml.Name               `xml:"myStruct"`
    Name    string                 `xml:"name"`
    Meta    map[string]interface{} `xml:"meta,omitempty"`
}

我在这里做了一个例子:http://play.golang.org/p/lTDJzXXPwT

我怎样才能做到这一点?

我的解决方法&#34;解决方案&#34;到目前为止:

http://play.golang.org/p/gQUlvkYl7k

基本上发生的是:

  1. Meta字段删除了xml注释,因此忽略了xml.Unmashal
  2. 使用字段创建新类型MapContainer:InnerXML [] byte xml:",innerxml"
  3. 使用xml:"meta,omitempty"注释添加MapContainer类型的MetaByte字段
  4. 因此,在第一个xml.Unmarshal中,我们保存了元元素XML的字节切片。然后在我们的自定义xml unmarshal函数中,我们获取byteSlice并使用mxj包中的magic函数NewMapXml,并将struct的Meta字段设置为这个新创建的映射。

    这要归功于天才制作了这个回购集https://github.com/clbanning/mxj,它可以从XML解组到地图。

    更新了当前的最佳解决方案:

    http://play.golang.org/p/_tw06klods

    感谢Adam Vincze

1 个答案:

答案 0 :(得分:2)

取决于你最后需要做什么,你可能想看看这个lib:https://github.com/clbanning/mxj

如果你实现一个自定义的UnmarshalXML函数

,你可以做得更好一些
func (m *MyStruct) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    var v struct {
        XMLName xml.Name `xml:"myStruct"`
        Name    string   `xml:"name"`
        Meta    struct {
            Inner []byte `xml:",innerxml"`
        } `xml:"meta"`
    }


    err := d.DecodeElement(&v, &start)
    if err != nil {
        return err
    }

    m.Name = v.Name
    myMap := make(map[string]interface{})
    // ... do the mxj magic here ... -
    // fill myMap
    m.Meta = myMap


    return nil
}

type MyStruct struct {
    Name    string
    Meta    map[string]interface{}
}

`

让你的MyStruct保持干净整洁