Dan
Dan

Reputation: 4663

Unmarshal XML with variable child types

I have XML that looks like this:

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<smses count="500">
  <sms id="1" text="hi" sms_specific_field="blah" />
  <sms id="2" text="what's up?" sms_specific_field="blah" />
  <mms id="3" text="null" text_only="0">
    <parts>
      <part seq="-1" content="image/jpeg" text="null" data="base64_data_here==" />
      <part seq="0" content="text/plain" text="Check it out!" />
    </parts>
  </mms>
  <sms id="4" text="what's up?" sms_specific_field="blah" />
</smses>

The sms and mms children of smses can occur in any order. I'd like to unmarshal this data into native Go structs. I thought I could use a slice of interfaces for those like:

Messages []interface{} `xml:",any"`  // not sure if this is correct

But then how do I get that into marshaled structs for each type?

I was thinking of approaching it like so but not sure if this works to cover both and don't want to spend all the time writing this for structs that will have a ton more attributes if this whole approach won't work anyways:

type Messages struct {
    XMLName       xml.Name   `xml:"smses"`
    Count         string     `xml:"count,attr"`
    MessageList   []Message  `xml:",any"` // <-- will this work?
}

type Message struct {
    SMS           SMS        `xml:"sms"`
    MMS           MMS        `xml:"mms"`
    ID            string     `xml"id,attr"`
    Text          string     `xml:"text,attr"`
}

type SMS struct {
    XMLName       xml.Name   `xml:"sms"`
    SMSSpecField  string     `xml:"sms_specific_field,attr"`
}

type MMS struct {
    XMLName       xml.Name   `xml:"mms"`
    TextOnly      string     `xml:"text_only,attr"`
    Parts         []Part     `xml:"parts"`
}

... And so on - but I don't know if this approach works / makes sense

How do I design my structs in order to unmarshal this XML including attributes and child items?

Upvotes: 1

Views: 576

Answers (1)

Adrian
Adrian

Reputation: 46423

One possible approach would be something like this:

type Messages struct {
    XMLName xml.Name `xml:"smses"`
    Count   string   `xml:"count,attr"`
    MMS     []MMS    `xml:"mms"`
    SMS     []SMS    `xml:"sms"`
}

This will unmarshal all child mms elements into MMS and all child sms elements into SMS. You can then iterate these for further processing as necessary, e.g. embedding them into Message objects and putting those into a combined slice. This will lose the original XML source order, however.

Upvotes: 1

Related Questions