Maybe something is missing for me, but is that what you are looking for?
I started with the same idea as @Manawasp (using the [string] {} map interface), but decided to try to get the name from the struct tag as you requested ... this is what I came up with (* Note: there may be some unhandled errors, and this can lead to an excessive compromise with the fact that you can easily cope with another solution)
http://play.golang.org/p/qO6tDZjtXA
package main import ( "fmt" "reflect" "strings" ) import ( "encoding/json" "encoding/xml" "errors" ) type Query struct { XMLName xml.Name `xml:"http://marklogic.com/appservices/search query" json:"-"` Field1 string Field2 int64 } type TermQuery struct { XMLName xml.Name `xml:"http://marklogic.com/appservices/search term-query" json:"-"` Field3 string Field4 int64 } func getXmlName(d interface{}, label string) (string, bool) { switch reflect.TypeOf(d).Kind() { case reflect.Struct: v, _ := reflect.TypeOf(d).FieldByName(label) parts := strings.Split(v.Tag.Get("xml"), " ") return parts[1], true } return "", false } func wrapJson(item interface{}) ([]byte, error) { if n, ok := getXmlName(item, "XMLName"); ok { b, err := json.Marshal(map[string]interface{}{n: item}) if err != nil { return nil, err } return b, nil } return nil, errors.New("You failed") } func main() {
OUTPUT
{"query":{"Field1":"hello","Field2":42}} {"term-query":{"Field3":"world","Field4":99}}
EDIT
Ok, now the update, and I see what this problem is. It may be ugly, and it may not be bulletproof (error handling, etc.) ... but for my test, it seems to do what you want.
http://play.golang.org/p/8MloLP3X4H
package main import ( "fmt" "reflect" "strings" ) import ( //"encoding/json" "encoding/json" "encoding/xml" "errors" ) type Query struct { XMLName xml.Name `xml:"http://marklogic.com/appservices/search query" json:"-"` Field1 string Field2 int64 Queries []interface{} `xml:",any" json:"queries"` } type TermQuery struct { XMLName xml.Name `xml:"http://marklogic.com/appservices/search term-query" json:"-"` Field3 string Field4 int64 } func getXmlName(d interface{}, label string) (string, bool) { switch reflect.TypeOf(d).Kind() { case reflect.Struct: v, _ := reflect.TypeOf(d).FieldByName(label) parts := strings.Split(v.Tag.Get("xml"), " ") return parts[1], true default: fmt.Println(reflect.TypeOf(d).Kind()) } return "", false } func wrapJson(item interface{}) (map[string]interface{}, error) { if n, ok := getXmlName(item, "XMLName"); ok { if k := reflect.ValueOf(item).FieldByName("Queries"); k.IsValid() { for i := 0; i < k.Len(); i++ { b, err1 := wrapJson(k.Index(i).Interface()) if err1 != nil { continue } k.Index(i).Set(reflect.ValueOf(b)) } } return map[string]interface{}{n: item}, nil } return nil, errors.New("You failed") } func asJson(i interface{}) []byte { b, err := json.Marshal(i) if err != nil { return []byte(`{"error": "too bad"}`) } return b } func main() {
PRETTY-PRINTED OUTOUT
{ "query": { "Field1": "hello", "Field2": 42, "queries": [ { "term-query": { "Field3": "world", "Field4": 99 } }, { "term-query": { "Field3": "yay, it works!", "Field4": 666 } }, { "query": { "Field1": "Hi", "Field2": 21, "queries": [ { "term-query": { "Field3": "omg", "Field4": 1 } } ] } } ] } }