Demi
Demi

Reputation: 3611

Unmarshalling heterogeneous list of XML elements in Go

I have an XML document like this:

<val>
<alpha β='γ'/>
<α δ='ε'/>
(a whole bunch of the above, in random order)
</val>

in other words, a heterogeneous list. I would like to unmarshal it using the Go encoding/xml package. How can I do this?

Upvotes: 3

Views: 340

Answers (1)

icza
icza

Reputation: 417662

You can't model such XML documents in Go, and you can't unmarshal into interace{}, so I would suggest event-driven parsing for this.

This event-driven parsing means when you are parsing (the tokens of) the XML document, you receive events like "start element encountered", or "end element encountered" (with details of the element of course), and these events control the flow of your program (branch and/or change internal state based on them).

The following example will show you the principle of this. It does not handle more complex XMLs because I wanted the example to be short, but this technique can be used to parse any XML documents.

Create an xml.Decoder using xml.NewDecoder(), and parse the content of the XML by calling Decoder.Token() repeatedly (in a loop).

The elements inside <val> will be collected in a slice of type []Entry:

type Entry struct {
    Name  string
    Attr  string
    Value string
}

func main() {
    decoder := xml.NewDecoder(strings.NewReader(src))

    entries := []Entry{}
    for {
        t, err := decoder.Token()
        if err != nil {
            if err != io.EOF {
                fmt.Println(err)
            }
            break
        }
        if se, ok := t.(xml.StartElement); ok && len(se.Attr) > 0 {
            entries = append(entries, Entry{
                Name:  se.Name.Local,
                Attr:  se.Attr[0].Name.Local,
                Value: se.Attr[0].Value,
            })
        }
    }

    fmt.Printf("%+v\n", entries)
}

const src = `<val>
<alpha β='γ'/>
<α δ='ε'/>
<x y='z'/>
</val>`

Output (try it on the Go Playground):

[{Name:alpha Attr:β Value:γ} {Name:α Attr:δ Value:ε} {Name:x Attr:y Value:z}]

Upvotes: 3

Related Questions