14 // UnmarshalXML deserializes an xml.Decoder into the container v. V
15 // needs to match the shape of the XML expected to be decoded.
16 // If the shape doesn't match unmarshaling will fail.
17 func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
18 n, err := XMLToStruct(d, nil)
22 if n.Children != nil {
23 for _, root := range n.Children {
24 for _, c := range root {
25 if wrappedChild, ok := c.Children[wrapper]; ok {
26 c = wrappedChild[0] // pull out wrapped element
29 err = parse(reflect.ValueOf(v), c, "")
43 // parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
44 // will be used to determine the type from r.
45 func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
47 if rtype.Kind() == reflect.Ptr {
48 rtype = rtype.Elem() // check kind of actual element type
65 if field, ok := rtype.FieldByName("_"); ok {
68 return parseStruct(r, node, tag)
70 return parseList(r, node, tag)
72 return parseMap(r, node, tag)
74 return parseScalar(r, node, tag)
78 // parseStruct deserializes a structure and its fields from an XMLNode. Any nested
79 // types in the structure will also be deserialized.
80 func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
82 if r.Kind() == reflect.Ptr {
83 if r.IsNil() { // create the structure if it's nil
84 s := reflect.New(r.Type().Elem())
93 // unwrap any payloads
94 if payload := tag.Get("payload"); payload != "" {
95 field, _ := t.FieldByName(payload)
96 return parseStruct(r.FieldByName(payload), node, field.Tag)
99 for i := 0; i < t.NumField(); i++ {
101 if c := field.Name[0:1]; strings.ToLower(c) == c {
102 continue // ignore unexported fields
105 // figure out what this field is called
107 if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
108 name = field.Tag.Get("locationNameList")
109 } else if locName := field.Tag.Get("locationName"); locName != "" {
113 // try to find the field by name in elements
114 elems := node.Children[name]
116 if elems == nil { // try to find the field in attributes
117 if val, ok := node.findElem(name); ok {
118 elems = []*XMLNode{{Text: val}}
122 member := r.FieldByName(field.Name)
123 for _, elem := range elems {
124 err := parse(member, elem, field.Tag)
133 // parseList deserializes a list of values from an XML node. Each list entry
134 // will also be deserialized.
135 func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
138 if tag.Get("flattened") == "" { // look at all item entries
140 if name := tag.Get("locationNameList"); name != "" {
144 if Children, ok := node.Children[mname]; ok {
146 r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
149 for i, c := range Children {
150 err := parse(r.Index(i), c, "")
156 } else { // flattened list means this is a single element
158 r.Set(reflect.MakeSlice(t, 0, 0))
161 childR := reflect.Zero(t.Elem())
162 r.Set(reflect.Append(r, childR))
163 err := parse(r.Index(r.Len()-1), node, "")
172 // parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
173 // will also be deserialized as map entries.
174 func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
176 r.Set(reflect.MakeMap(r.Type()))
179 if tag.Get("flattened") == "" { // look at all child entries
180 for _, entry := range node.Children["entry"] {
181 parseMapEntry(r, entry, tag)
183 } else { // this element is itself an entry
184 parseMapEntry(r, node, tag)
190 // parseMapEntry deserializes a map entry from a XML node.
191 func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
192 kname, vname := "key", "value"
193 if n := tag.Get("locationNameKey"); n != "" {
196 if n := tag.Get("locationNameValue"); n != "" {
200 keys, ok := node.Children[kname]
201 values := node.Children[vname]
203 for i, key := range keys {
204 keyR := reflect.ValueOf(key.Text)
206 valueR := reflect.New(r.Type().Elem()).Elem()
208 parse(valueR, value, "")
209 r.SetMapIndex(keyR, valueR)
215 // parseScaller deserializes an XMLNode value into a concrete type based on the
216 // interface type of r.
218 // Error is returned if the deserialization fails due to invalid type conversion,
219 // or unsupported interface type.
220 func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
221 switch r.Interface().(type) {
223 r.Set(reflect.ValueOf(&node.Text))
226 b, err := base64.StdEncoding.DecodeString(node.Text)
230 r.Set(reflect.ValueOf(b))
232 v, err := strconv.ParseBool(node.Text)
236 r.Set(reflect.ValueOf(&v))
238 v, err := strconv.ParseInt(node.Text, 10, 64)
242 r.Set(reflect.ValueOf(&v))
244 v, err := strconv.ParseFloat(node.Text, 64)
248 r.Set(reflect.ValueOf(&v))
250 const ISO8601UTC = "2006-01-02T15:04:05Z"
251 t, err := time.Parse(ISO8601UTC, node.Text)
255 r.Set(reflect.ValueOf(&t))
257 return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())