Unmarshal XML element to interface{}

1,919 views
Skip to first unread message

hajd...@gmail.com

unread,
Aug 20, 2015, 12:52:45 PM8/20/15
to golang-nuts
Is there any reason this *shouldn't* work? ( I realize it doesn't, just curious since you can marshal an empty interface ).

A contrived example: ( https://play.golang.org/p/s-Lh0qDwAP)

type Person struct {
XMLName   xml.Name    `xml:"person"`
FirstName string      `xml:"firstname"`
Parents interface{} `xml:"parent"`
}

func main() {
type Parent struct {
FirstName string `xml:"name"`
LastName string `xml:"lastname"`
}
p := &Person{FirstName: "Steve"}
p.Parents = []Parent{Parent{"Jack","Doe"}, Parent{"Lynne","Doe"}}
data, err := xml.Marshal(p)
if err != nil {
fmt.Println(err)
}
fmt.Println("Marshalled:",string(data))
p2 := &Person{}
p2.Parents = []Parent{}
err = xml.Unmarshal(data, p2)
if err != nil {
fmt.Println(err)
}
fmt.Println("Unmarshalled:", p2)
}


I get that by being an empty interface{}, there are no fields that are exported for it to look at.  Except that I'm assigning a concrete type to the interface{}, so shouldn't Unmarshal be able to reflect that interface{} and find the struct/tag names to Unmarshal the data?  I'm assuming ( and guessing I'm wrong ) that that's how Marshal does it?  I think I'd probably be less confused if Marshal wasn't working as well, but I don't get why Marshal can deal with a interface{} and Unmarshal can't.

The real use case I have being that the XML response I'm getting has some static elements and then it has dynamic elements:

<api>
  <staticfield1>data</staticfield1>
  <staticfield2>data</staticfield2>
  <record>
    <fieldname1>data</fieldname1>
    <fieldname2>data</fieldname2>
  </record>
  <record>
    ..
  </record>
</api>

I have the static fields in a struct, but fieldname's returned in the record elements change, depending on which database table is being returned by the api.  I want to be able to create a record struct that matches what I know the record will look like for each call, and then compose the whole struct ( static fields + the dynamic fields ) that I'm unmarshalling into.

The solution I have right now is to have a byte array that captures the innerxml and then unmarshal that separately, but I felt like this would be a cleaner solution.  ( https://play.golang.org/p/z3BS6tjqgW )

If there isn't anyway to do this - is there anyway to grab a whole <parent> record, with the <parent></parent> tags included?  My byte solution works, but the issue I run into is that my innerxml field just ends up with <FirstName></FirstName><LastName></LastName>, with no surrounding <parent> tags.  So I have to add the parent tags back so that I can unmarshal to a Parent struct, as you can see in the example.

Any help appreciated!

Steve

Matt Harden

unread,
Aug 20, 2015, 2:01:38 PM8/20/15
to hajd...@gmail.com, golang-nuts

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

hajd...@gmail.com

unread,
Aug 20, 2015, 5:27:30 PM8/20/15
to golang-nuts, hajd...@gmail.com
Thanks Matt,

I had already tried doing it that way and had run into some issues.  After your post, I tried it again and I must have had something else wrong before, because it worked this time.

I do wish there was still a way to allow interface{} to be Unmarshalled.  It'd be nice to have a function that could compose the struct, rather than forcing the end user of my library to make their own composed struct and pass it along to the library call.

Matt Harden

unread,
Aug 20, 2015, 7:39:45 PM8/20/15
to hajd...@gmail.com, golang-nuts

You can do that by implementing your own UnmarshalXML method: https://play.golang.org/p/uoim__Qpeu. You have to make sure to store a pointer to a slice in the interface or else Unmarshal will produce an error. You could only get around *that* limitation by using reflection.

luiz....@gmail.com

unread,
May 14, 2020, 12:28:51 PM5/14/20
to golang-nuts
Dude, thanks a lot! Really really really a lot.
To unsubscribe from this group and stop receiving emails from it, send an email to golan...@googlegroups.com.

Saied Seghatoleslami

unread,
May 14, 2020, 3:58:48 PM5/14/20
to golang-nuts
I have tried unmarshalling various JSON and XML files with limited success.  So I ended up writing a "lexer" along the lines of Rob Pike's lecture in Australia.  I have had good success with it in a bunch of projects.  I would be very interested to get some comments on what the community thinks of decoding XML, JSON and similarly encoded objects in this way.  https://github.com/Saied74/lexer2

Muse254

unread,
Nov 8, 2020, 9:33:04 PM11/8/20
to golang-nuts
@[matt....@gmail.com] deserves a beer, I really needed to unmarshal to an interface
Reply all
Reply to author
Forward
0 new messages