编组 JSON 编组兼容映射到 XML

Marshal a JSON Marshal compatible map to XML

我有一张地图:[]map[string]string

json.marshal() 兼容对象中填充结果。输出:

[
  {
    "key1": "val1",
    "key2": "val2"
  },
  {
    "randval3": "val1",
    "randval2": "xyz1"
    "randval1": "xyz3"
  },
  ...
]

但是,当我运行xml.marshal()。我收到 xml: unsupported type: map[string]string。鉴于 XML 需要节点名称等事实,这似乎是合理的。所以我基本上正在寻找的是一种获取方式:

<rootElement>
    <child>
        <key1>val1</key1>
        <key2>val1</key2>
    </child>
    <child>
        <randval3>val1</randval3>
        <randval2>xyz1</randval2>
        <randval1>xyz1</randval1>
    </child>
</rootElement>

但我无法获得与 xml.unmarshal()

兼容的 'object'

您可以声明一个自定义地图并让它实现 xml.Marshaler 接口。

type mymap map[string]string

func (m mymap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    if err := e.EncodeToken(start); err != nil {
        return err
    }

    for key, val := range m {
        s := xml.StartElement{Name: xml.Name{Local: key}}
        if err := e.EncodeElement(val, s); err != nil {
            return err
        }
    }

    return e.EncodeToken(start.End())
}

type RootElement struct {
    XMLName  xml.Name `xml:"rootElement"`
    Children []mymap  `xml:"child"`
} 

https://play.golang.com/p/0_qA9UUvhKV

func main() {
    root := RootElement{Children: []mymap{
        {"key1": "val1", "key2": "val2"},
        {"randval1": "val1", "randval2": "xyz1", "randval3": "abc3"},
    }}

    data, err := xml.MarshalIndent(root, "", "  ")
    if err != nil {
        panic(err)
    }
    fmt.Println(string(data))
}

输出:

<rootElement>
  <child>
    <key2>val2</key2>
    <key1>val1</key1>
  </child>
  <child>
    <randval3>abc3</randval3>
    <randval1>val1</randval1>
    <randval2>xyz1</randval2>
  </child>
</rootElement>

对于 Marshalling/Unmarshalling 地图,您需要编写自己的 Marshal()Unmarshal() 函数。

下面是为 type Maps []map[string]string 实现这些功能以及如何使用它们的示例。

type Maps []map[string]string

type xmlMapEntry struct {
    XMLName xml.Name
    Value   string `xml:",chardata"`
}

func (m Maps) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    if len(m) == 0 {
        return nil
    }

    err := e.EncodeToken(start)
    if err != nil {
        return err
    }

    for _, ma := range m {
        for k, v := range ma {
            e.Encode(xmlMapEntry{XMLName: xml.Name{Local: k}, Value: v})
        }
    }

    return e.EncodeToken(start.End())
}

func (m *Maps) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    *m = Maps{}

    for {
        var e xmlMapEntry

        err := d.Decode(&e)
        if err == io.EOF {
            break
        } else if err != nil {
            return err
        }

        *m = append(*m, map[string]string{e.XMLName.Local: e.Value})
    }
    return nil
}

func main() {
    myarraymap := []map[string]string{
        0: {"Key1": "val1"},
        1: {"Key2": "val2"},
        2: {"Randval3": "val1"},
        3: {"Randval2": "xyz1"},
        4: {"Randval1": "xyz2"},
    }

    // Encode to XML
    x, _ := xml.MarshalIndent(Maps(myarraymap), "", "  ")
    fmt.Printf("my marshaled xml map: %v\n", string(x))


    // Decode back from XML
    var rm []map[string]string
    xml.Unmarshal(x, (*Maps)(&rm))
    fmt.Printf("my unmarshalled xml map: %v \n", rm)
}