Маршал JSON Маршалл совместимая карта с XML - PullRequest
0 голосов
/ 17 апреля 2020

У меня есть карта: []map[string]string.

Заполнение результатов в json.marshal() совместимом объекте. Вывод:

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

Однако, когда я запускаю xml.marshal(). Я получаю xml: unsupported type: map[string]string. Что кажется разумным, учитывая тот факт, что XML нужны имена узлов и т. Д. c. Так что я в основном ищу способ получить:

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

Но я застреваю с получением «объекта», совместимого с xml.unmarshal()

Ответы [ 2 ]

0 голосов
/ 17 апреля 2020

Для карт 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)
}
0 голосов
/ 17 апреля 2020

Вы можете объявить пользовательскую карту и заставить ее реализовать интерфейс 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>
...