diff options
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.go | 260 |
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 @@ | |||
1 | package xmlutil | ||
2 | |||
3 | import ( | ||
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. | ||
17 | func 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. | ||
45 | func 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. | ||
80 | func 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. | ||
135 | func 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. | ||
174 | func 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. | ||
191 | func 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. | ||
220 | func 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 | } | ||