aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go')
-rw-r--r--vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go260
1 files changed, 260 insertions, 0 deletions
diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go
new file mode 100644
index 0000000..8758462
--- /dev/null
+++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/unmarshal.go
@@ -0,0 +1,260 @@
1package xmlutil
2
3import (
4 "encoding/base64"
5 "encoding/xml"
6 "fmt"
7 "io"
8 "reflect"
9 "strconv"
10 "strings"
11 "time"
12)
13
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.
17func UnmarshalXML(v interface{}, d *xml.Decoder, wrapper string) error {
18 n, err := XMLToStruct(d, nil)
19 if err != nil {
20 return err
21 }
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
27 }
28
29 err = parse(reflect.ValueOf(v), c, "")
30 if err != nil {
31 if err == io.EOF {
32 return nil
33 }
34 return err
35 }
36 }
37 }
38 return nil
39 }
40 return nil
41}
42
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.
45func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
46 rtype := r.Type()
47 if rtype.Kind() == reflect.Ptr {
48 rtype = rtype.Elem() // check kind of actual element type
49 }
50
51 t := tag.Get("type")
52 if t == "" {
53 switch rtype.Kind() {
54 case reflect.Struct:
55 t = "structure"
56 case reflect.Slice:
57 t = "list"
58 case reflect.Map:
59 t = "map"
60 }
61 }
62
63 switch t {
64 case "structure":
65 if field, ok := rtype.FieldByName("_"); ok {
66 tag = field.Tag
67 }
68 return parseStruct(r, node, tag)
69 case "list":
70 return parseList(r, node, tag)
71 case "map":
72 return parseMap(r, node, tag)
73 default:
74 return parseScalar(r, node, tag)
75 }
76}
77
78// parseStruct deserializes a structure and its fields from an XMLNode. Any nested
79// types in the structure will also be deserialized.
80func parseStruct(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
81 t := r.Type()
82 if r.Kind() == reflect.Ptr {
83 if r.IsNil() { // create the structure if it's nil
84 s := reflect.New(r.Type().Elem())
85 r.Set(s)
86 r = s
87 }
88
89 r = r.Elem()
90 t = t.Elem()
91 }
92
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)
97 }
98
99 for i := 0; i < t.NumField(); i++ {
100 field := t.Field(i)
101 if c := field.Name[0:1]; strings.ToLower(c) == c {
102 continue // ignore unexported fields
103 }
104
105 // figure out what this field is called
106 name := field.Name
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 != "" {
110 name = locName
111 }
112
113 // try to find the field by name in elements
114 elems := node.Children[name]
115
116 if elems == nil { // try to find the field in attributes
117 if val, ok := node.findElem(name); ok {
118 elems = []*XMLNode{{Text: val}}
119 }
120 }
121
122 member := r.FieldByName(field.Name)
123 for _, elem := range elems {
124 err := parse(member, elem, field.Tag)
125 if err != nil {
126 return err
127 }
128 }
129 }
130 return nil
131}
132
133// parseList deserializes a list of values from an XML node. Each list entry
134// will also be deserialized.
135func parseList(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
136 t := r.Type()
137
138 if tag.Get("flattened") == "" { // look at all item entries
139 mname := "member"
140 if name := tag.Get("locationNameList"); name != "" {
141 mname = name
142 }
143
144 if Children, ok := node.Children[mname]; ok {
145 if r.IsNil() {
146 r.Set(reflect.MakeSlice(t, len(Children), len(Children)))
147 }
148
149 for i, c := range Children {
150 err := parse(r.Index(i), c, "")
151 if err != nil {
152 return err
153 }
154 }
155 }
156 } else { // flattened list means this is a single element
157 if r.IsNil() {
158 r.Set(reflect.MakeSlice(t, 0, 0))
159 }
160
161 childR := reflect.Zero(t.Elem())
162 r.Set(reflect.Append(r, childR))
163 err := parse(r.Index(r.Len()-1), node, "")
164 if err != nil {
165 return err
166 }
167 }
168
169 return nil
170}
171
172// parseMap deserializes a map from an XMLNode. The direct children of the XMLNode
173// will also be deserialized as map entries.
174func parseMap(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
175 if r.IsNil() {
176 r.Set(reflect.MakeMap(r.Type()))
177 }
178
179 if tag.Get("flattened") == "" { // look at all child entries
180 for _, entry := range node.Children["entry"] {
181 parseMapEntry(r, entry, tag)
182 }
183 } else { // this element is itself an entry
184 parseMapEntry(r, node, tag)
185 }
186
187 return nil
188}
189
190// parseMapEntry deserializes a map entry from a XML node.
191func parseMapEntry(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
192 kname, vname := "key", "value"
193 if n := tag.Get("locationNameKey"); n != "" {
194 kname = n
195 }
196 if n := tag.Get("locationNameValue"); n != "" {
197 vname = n
198 }
199
200 keys, ok := node.Children[kname]
201 values := node.Children[vname]
202 if ok {
203 for i, key := range keys {
204 keyR := reflect.ValueOf(key.Text)
205 value := values[i]
206 valueR := reflect.New(r.Type().Elem()).Elem()
207
208 parse(valueR, value, "")
209 r.SetMapIndex(keyR, valueR)
210 }
211 }
212 return nil
213}
214
215// parseScaller deserializes an XMLNode value into a concrete type based on the
216// interface type of r.
217//
218// Error is returned if the deserialization fails due to invalid type conversion,
219// or unsupported interface type.
220func parseScalar(r reflect.Value, node *XMLNode, tag reflect.StructTag) error {
221 switch r.Interface().(type) {
222 case *string:
223 r.Set(reflect.ValueOf(&node.Text))
224 return nil
225 case []byte:
226 b, err := base64.StdEncoding.DecodeString(node.Text)
227 if err != nil {
228 return err
229 }
230 r.Set(reflect.ValueOf(b))
231 case *bool:
232 v, err := strconv.ParseBool(node.Text)
233 if err != nil {
234 return err
235 }
236 r.Set(reflect.ValueOf(&v))
237 case *int64:
238 v, err := strconv.ParseInt(node.Text, 10, 64)
239 if err != nil {
240 return err
241 }
242 r.Set(reflect.ValueOf(&v))
243 case *float64:
244 v, err := strconv.ParseFloat(node.Text, 64)
245 if err != nil {
246 return err
247 }
248 r.Set(reflect.ValueOf(&v))
249 case *time.Time:
250 const ISO8601UTC = "2006-01-02T15:04:05Z"
251 t, err := time.Parse(ISO8601UTC, node.Text)
252 if err != nil {
253 return err
254 }
255 r.Set(reflect.ValueOf(&t))
256 default:
257 return fmt.Errorf("unsupported value: %v (%s)", r.Interface(), r.Type())
258 }
259 return nil
260}