Willem
Willem

Reputation: 3253

Golang xml.Unmarshall arbitrary elements

XML with arbitrary number of arbitrarily named elements:

<modules>
<elt1><version>1.2.3</version></elt1>
<eltN><version>4.5.6</version></eltN>
</modules>

How to parse this into a map[string]string for elementname to version? All Unmarshall examples that I found, assume static element names.

Upvotes: 2

Views: 447

Answers (1)

P Varga
P Varga

Reputation: 20229

You could use xml.Decoder instead: Example, which severely lacks error handling.

package main

import (
    "encoding/xml"
    "fmt"
    "io"
    "strings"
)

func main() {
    data := `<modules>
         <elt1><version>1.2.3</version></elt1>
         <eltN><version>4.5.6</version></eltN>
         </modules>`
    fmt.Println(parseVersions(strings.NewReader(data)))
}

func parseVersions(s io.Reader) map[string]string {
    r := make(map[string]string)
    decoder := xml.NewDecoder(s)
    for token, err := decoder.Token(); err == nil; token, err = decoder.Token() {
        switch v := token.(type) {
        case xml.StartElement:
            if el := v.Name.Local; strings.HasPrefix(el, "elt") {
                r[el] = parseVersion(decoder)
            }
        }
    }
    return r
}

func parseVersion(decoder *xml.Decoder) string {
    token, _ := decoder.Token()
    switch v := token.(type) {
    case xml.StartElement:
        if v.Name.Local == "version" {
            cd, _ := decoder.Token()
            return string(cd.(xml.CharData))
        }
    }
    return ""
}

Upvotes: 3

Related Questions