13 "github.com/aws/aws-sdk-go/private/protocol"
16 // UnmarshalXML deserializes an xml.Decoder into the container v. V
17 // needs to match the shape of the XML expected to be decoded.
18 // If the shape doesn't match unmarshaling will fail.
19 func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
20 n, err := XMLToStruct(d, nil)
24 if n.Children != nil {
25 for _, root := range n.Children {
26 for _, c := range root {
27 if wrappedChild, ok := c.Children[wrapper]; ok {
28 c = wrappedChild[0] // pull out wrapped element
31 err = parse(reflect.ValueOf(v), c, "")
45 // parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
46 // will be used to determine the type from r.
47 func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
49 if rtype.Kind() == reflect.Ptr {
50 rtype = rtype.Elem() // check kind of actual element type
57 // also it can't be a time object
58 if _, ok := r.Interface().(*time.Time); !ok {
62 // also it can't be a byte slice
63 if _, ok := r.Interface().([]byte); !ok {
73 if field, ok := rtype.FieldByName("_"); ok {
76 return parseStruct(r, node, tag)
78 return parseList(r, node, tag)
80 return parseMap(r, node, tag)
82 return parseScalar(r, node, tag)
86 // parseStruct deserializes a structure and its fields from an XMLNode. Any nested
87 // types in the structure will also be deserialized.
88 func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
90 if r.Kind() == reflect.Ptr {
91 if r.IsNil() { // create the structure if it's nil
92 s := reflect.New(r.Type().Elem())
101 // unwrap any payloads
102 if payload := tag.Get("payload"); payload != "" {
103 field, _ := t.FieldByName(payload)
104 return parseStruct(r.FieldByName(payload), node, field.Tag)
107 for i := 0; i < t.NumField(); i++ {
109 if c := field.Name[0:1]; strings.ToLower(c) == c {
110 continue // ignore unexported fields
113 // figure out what this field is called
115 if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
116 name = field.Tag.Get("locationNameList")
117 } else if locName := field.Tag.Get("locationName"); locName != "" {
121 // try to find the field by name in elements
122 elems := node.Children[name]
124 if elems == nil { // try to find the field in attributes
125 if val, ok := node.findElem(name); ok {
126 elems = []*XMLNode{{Text: val}}
130 member := r.FieldByName(field.Name)
131 for _, elem := range elems {
132 err := parse(member, elem, field.Tag)
141 // parseList deserializes a list of values from an XML node. Each list entry
142 // will also be deserialized.
143 func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
146 if tag.Get("flattened") == "" { // look at all item entries
148 if name := tag.Get("locationNameList"); name != "" {
152 if Children, ok := node.Children[mname]; ok {
154 r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
157 for i, c := range Children {
158 err := parse(r.Index(i), c, "")
164 } else { // flattened list means this is a single element
166 r.Set(reflect.MakeSlice(t, 0, 0))
169 childR := reflect.Zero(t.Elem())
170 r.Set(reflect.Append(r, childR))
171 err := parse(r.Index(r.Len()-1), node, "")
180 // parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
181 // will also be deserialized as map entries.
182 func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
184 r.Set(reflect.MakeMap(r.Type()))
187 if tag.Get("flattened") == "" { // look at all child entries
188 for _, entry := range node.Children["entry"] {
189 parseMapEntry(r, entry, tag)
191 } else { // this element is itself an entry
192 parseMapEntry(r, node, tag)
198 // parseMapEntry deserializes a map entry from a XML node.
199 func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
200 kname, vname := "key", "value"
201 if n := tag.Get("locationNameKey"); n != "" {
204 if n := tag.Get("locationNameValue"); n != "" {
208 keys, ok := node.Children[kname]
209 values := node.Children[vname]
211 for i, key := range keys {
212 keyR := reflect.ValueOf(key.Text)
214 valueR := reflect.New(r.Type().Elem()).Elem()
216 parse(valueR, value, "")
217 r.SetMapIndex(keyR, valueR)
223 // parseScaller deserializes an XMLNode value into a concrete type based on the
224 // interface type of r.
226 // Error is returned if the deserialization fails due to invalid type conversion,
227 // or unsupported interface type.
228 func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
229 switch r.Interface().(type) {
231 r.Set(reflect.ValueOf(&node.Text))
234 b, err := base64.StdEncoding.DecodeString(node.Text)
238 r.Set(reflect.ValueOf(b))
240 v, err := strconv.ParseBool(node.Text)
244 r.Set(reflect.ValueOf(&v))
246 v, err := strconv.ParseInt(node.Text, 10, 64)
250 r.Set(reflect.ValueOf(&v))
252 v, err := strconv.ParseFloat(node.Text, 64)
256 r.Set(reflect.ValueOf(&v))
258 format := tag.Get("timestampFormat")
259 if len(format) == 0 {
260 format = protocol.ISO8601TimeFormatName
263 t, err := protocol.ParseTime(format, node.Text)
267 r.Set(reflect.ValueOf(&t))
269 return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())