14 "github.com/aws/aws-sdk-go/aws/awserr"
15 "github.com/aws/aws-sdk-go/private/protocol"
18 // UnmarshalXMLError unmarshals the XML error from the stream into the value
19 // type specified. The value must be a pointer. If the message fails to
20 // unmarshal, the message content will be included in the returned error as a
21 // awserr.UnmarshalError.
22 func UnmarshalXMLError(v interface{}, stream io.Reader) error {
23 var errBuf bytes.Buffer
24 body := io.TeeReader(stream, &errBuf)
26 err := xml.NewDecoder(body).Decode(v)
27 if err != nil && err != io.EOF {
28 return awserr.NewUnmarshalError(err,
29 "failed to unmarshal error message", errBuf.Bytes())
35 // UnmarshalXML deserializes an xml.Decoder into the container v. V
36 // needs to match the shape of the XML expected to be decoded.
37 // If the shape doesn't match unmarshaling will fail.
38 func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
39 n, err := XMLToStruct(d, nil)
43 if n.Children != nil {
44 for _, root := range n.Children {
45 for _, c := range root {
46 if wrappedChild, ok := c.Children[wrapper]; ok {
47 c = wrappedChild[0] // pull out wrapped element
50 err = parse(reflect.ValueOf(v), c, "")
64 // parse deserializes any value from the XMLNode. The type tag is used to infer the type, or reflect
65 // will be used to determine the type from r.
66 func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
68 if rtype.Kind() == reflect.Ptr {
69 rtype = rtype.Elem() // check kind of actual element type
76 // also it can't be a time object
77 if _, ok := r.Interface().(*time.Time); !ok {
81 // also it can't be a byte slice
82 if _, ok := r.Interface().([]byte); !ok {
92 if field, ok := rtype.FieldByName("_"); ok {
95 return parseStruct(r, node, tag)
97 return parseList(r, node, tag)
99 return parseMap(r, node, tag)
101 return parseScalar(r, node, tag)
105 // parseStruct deserializes a structure and its fields from an XMLNode. Any nested
106 // types in the structure will also be deserialized.
107 func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
109 if r.Kind() == reflect.Ptr {
110 if r.IsNil() { // create the structure if it's nil
111 s := reflect.New(r.Type().Elem())
120 // unwrap any payloads
121 if payload := tag.Get("payload"); payload != "" {
122 field, _ := t.FieldByName(payload)
123 return parseStruct(r.FieldByName(payload), node, field.Tag)
126 for i := 0; i < t.NumField(); i++ {
128 if c := field.Name[0:1]; strings.ToLower(c) == c {
129 continue // ignore unexported fields
132 // figure out what this field is called
134 if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
135 name = field.Tag.Get("locationNameList")
136 } else if locName := field.Tag.Get("locationName"); locName != "" {
140 // try to find the field by name in elements
141 elems := node.Children[name]
143 if elems == nil { // try to find the field in attributes
144 if val, ok := node.findElem(name); ok {
145 elems = []*XMLNode{{Text: val}}
149 member := r.FieldByName(field.Name)
150 for _, elem := range elems {
151 err := parse(member, elem, field.Tag)
160 // parseList deserializes a list of values from an XML node. Each list entry
161 // will also be deserialized.
162 func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
165 if tag.Get("flattened") == "" { // look at all item entries
167 if name := tag.Get("locationNameList"); name != "" {
171 if Children, ok := node.Children[mname]; ok {
173 r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
176 for i, c := range Children {
177 err := parse(r.Index(i), c, "")
183 } else { // flattened list means this is a single element
185 r.Set(reflect.MakeSlice(t, 0, 0))
188 childR := reflect.Zero(t.Elem())
189 r.Set(reflect.Append(r, childR))
190 err := parse(r.Index(r.Len()-1), node, "")
199 // parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
200 // will also be deserialized as map entries.
201 func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
203 r.Set(reflect.MakeMap(r.Type()))
206 if tag.Get("flattened") == "" { // look at all child entries
207 for _, entry := range node.Children["entry"] {
208 parseMapEntry(r, entry, tag)
210 } else { // this element is itself an entry
211 parseMapEntry(r, node, tag)
217 // parseMapEntry deserializes a map entry from a XML node.
218 func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
219 kname, vname := "key", "value"
220 if n := tag.Get("locationNameKey"); n != "" {
223 if n := tag.Get("locationNameValue"); n != "" {
227 keys, ok := node.Children[kname]
228 values := node.Children[vname]
230 for i, key := range keys {
231 keyR := reflect.ValueOf(key.Text)
233 valueR := reflect.New(r.Type().Elem()).Elem()
235 parse(valueR, value, "")
236 r.SetMapIndex(keyR, valueR)
242 // parseScaller deserializes an XMLNode value into a concrete type based on the
243 // interface type of r.
245 // Error is returned if the deserialization fails due to invalid type conversion,
246 // or unsupported interface type.
247 func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
248 switch r.Interface().(type) {
250 r.Set(reflect.ValueOf(&node.Text))
253 b, err := base64.StdEncoding.DecodeString(node.Text)
257 r.Set(reflect.ValueOf(b))
259 v, err := strconv.ParseBool(node.Text)
263 r.Set(reflect.ValueOf(&v))
265 v, err := strconv.ParseInt(node.Text, 10, 64)
269 r.Set(reflect.ValueOf(&v))
271 v, err := strconv.ParseFloat(node.Text, 64)
275 r.Set(reflect.ValueOf(&v))
277 format := tag.Get("timestampFormat")
278 if len(format) == 0 {
279 format = protocol.ISO8601TimeFormatName
282 t, err := protocol.ParseTime(format, node.Text)
286 r.Set(reflect.ValueOf(&t))
288 return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())