2015-07-01 1 views
1

Проблема в том, что xml.Unmarshal структуры с полем типа map [string] interface {} завершится с ошибкой :Ошибка при попытке xml.Unmarshal для структуры с полем типа map [string] interface {}

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

поскольку Meta поле типа карты [строка] интерфейс {} является, насколько я могу определить, что внутри должно быть динамически unmarshalled.

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

Как я могу добиться этого?


Мой обходной путь "решение" до сих пор:

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

В основном то, что происходит в том, что:

  1. Мета поле получил XML-аннотаций удалены, таким образом, будучи игнорировать от xml.Unmashal
  2. Новый тип, MapContainer, является создано с полем: InnerXml [] байты xml:",innerxml"
  3. MetaByte поле типа MapContainer добавляется с помощью xml:"meta,omitempty" аннотаций

Таким образом, в первом xml.Unmarshal мы сохранить байты куски XML мета элемента. Затем в нашей специальной функции xml unmarshal мы берем этот byteSlice и используем магическую функцию NewMapXml из пакета mxj и устанавливаем мета-поле структуры на эту вновь созданную карту.

Это возможно благодаря тому, что гений сделал это репо, https://github.com/clbanning/mxj, которое может отменить XML с помощью карт.

Обновленный тока лучшее решение:

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

Благодаря Адам Vincze

+0

Вы могли бы найти это полезным: [? Как пройти через данные XML в Golang] (http://stackoverflow.com/questions/30256729/как к траверсе-через-XML-данных в-golang) – icza

ответ

2

в зависимости, что вам нужно сделать с мета в конце концов, вы можете захотеть взглянуть на этой библиотеки: 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 красивый и чистый

Смежные вопросы