diff options
Diffstat (limited to 'vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go')
-rw-r--r-- | vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go b/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go new file mode 100644 index 0000000..3e970b6 --- /dev/null +++ b/vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go | |||
@@ -0,0 +1,147 @@ | |||
1 | package xmlutil | ||
2 | |||
3 | import ( | ||
4 | "encoding/xml" | ||
5 | "fmt" | ||
6 | "io" | ||
7 | "sort" | ||
8 | ) | ||
9 | |||
10 | // A XMLNode contains the values to be encoded or decoded. | ||
11 | type XMLNode struct { | ||
12 | Name xml.Name `json:",omitempty"` | ||
13 | Children map[string][]*XMLNode `json:",omitempty"` | ||
14 | Text string `json:",omitempty"` | ||
15 | Attr []xml.Attr `json:",omitempty"` | ||
16 | |||
17 | namespaces map[string]string | ||
18 | parent *XMLNode | ||
19 | } | ||
20 | |||
21 | // NewXMLElement returns a pointer to a new XMLNode initialized to default values. | ||
22 | func NewXMLElement(name xml.Name) *XMLNode { | ||
23 | return &XMLNode{ | ||
24 | Name: name, | ||
25 | Children: map[string][]*XMLNode{}, | ||
26 | Attr: []xml.Attr{}, | ||
27 | } | ||
28 | } | ||
29 | |||
30 | // AddChild adds child to the XMLNode. | ||
31 | func (n *XMLNode) AddChild(child *XMLNode) { | ||
32 | if _, ok := n.Children[child.Name.Local]; !ok { | ||
33 | n.Children[child.Name.Local] = []*XMLNode{} | ||
34 | } | ||
35 | n.Children[child.Name.Local] = append(n.Children[child.Name.Local], child) | ||
36 | } | ||
37 | |||
38 | // XMLToStruct converts a xml.Decoder stream to XMLNode with nested values. | ||
39 | func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) { | ||
40 | out := &XMLNode{} | ||
41 | for { | ||
42 | tok, err := d.Token() | ||
43 | if err != nil { | ||
44 | if err == io.EOF { | ||
45 | break | ||
46 | } else { | ||
47 | return out, err | ||
48 | } | ||
49 | } | ||
50 | |||
51 | if tok == nil { | ||
52 | break | ||
53 | } | ||
54 | |||
55 | switch typed := tok.(type) { | ||
56 | case xml.CharData: | ||
57 | out.Text = string(typed.Copy()) | ||
58 | case xml.StartElement: | ||
59 | el := typed.Copy() | ||
60 | out.Attr = el.Attr | ||
61 | if out.Children == nil { | ||
62 | out.Children = map[string][]*XMLNode{} | ||
63 | } | ||
64 | |||
65 | name := typed.Name.Local | ||
66 | slice := out.Children[name] | ||
67 | if slice == nil { | ||
68 | slice = []*XMLNode{} | ||
69 | } | ||
70 | node, e := XMLToStruct(d, &el) | ||
71 | out.findNamespaces() | ||
72 | if e != nil { | ||
73 | return out, e | ||
74 | } | ||
75 | node.Name = typed.Name | ||
76 | node.findNamespaces() | ||
77 | tempOut := *out | ||
78 | // Save into a temp variable, simply because out gets squashed during | ||
79 | // loop iterations | ||
80 | node.parent = &tempOut | ||
81 | slice = append(slice, node) | ||
82 | out.Children[name] = slice | ||
83 | case xml.EndElement: | ||
84 | if s != nil && s.Name.Local == typed.Name.Local { // matching end token | ||
85 | return out, nil | ||
86 | } | ||
87 | out = &XMLNode{} | ||
88 | } | ||
89 | } | ||
90 | return out, nil | ||
91 | } | ||
92 | |||
93 | func (n *XMLNode) findNamespaces() { | ||
94 | ns := map[string]string{} | ||
95 | for _, a := range n.Attr { | ||
96 | if a.Name.Space == "xmlns" { | ||
97 | ns[a.Value] = a.Name.Local | ||
98 | } | ||
99 | } | ||
100 | |||
101 | n.namespaces = ns | ||
102 | } | ||
103 | |||
104 | func (n *XMLNode) findElem(name string) (string, bool) { | ||
105 | for node := n; node != nil; node = node.parent { | ||
106 | for _, a := range node.Attr { | ||
107 | namespace := a.Name.Space | ||
108 | if v, ok := node.namespaces[namespace]; ok { | ||
109 | namespace = v | ||
110 | } | ||
111 | if name == fmt.Sprintf("%s:%s", namespace, a.Name.Local) { | ||
112 | return a.Value, true | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | return "", false | ||
117 | } | ||
118 | |||
119 | // StructToXML writes an XMLNode to a xml.Encoder as tokens. | ||
120 | func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error { | ||
121 | e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr}) | ||
122 | |||
123 | if node.Text != "" { | ||
124 | e.EncodeToken(xml.CharData([]byte(node.Text))) | ||
125 | } else if sorted { | ||
126 | sortedNames := []string{} | ||
127 | for k := range node.Children { | ||
128 | sortedNames = append(sortedNames, k) | ||
129 | } | ||
130 | sort.Strings(sortedNames) | ||
131 | |||
132 | for _, k := range sortedNames { | ||
133 | for _, v := range node.Children[k] { | ||
134 | StructToXML(e, v, sorted) | ||
135 | } | ||
136 | } | ||
137 | } else { | ||
138 | for _, c := range node.Children { | ||
139 | for _, v := range c { | ||
140 | StructToXML(e, v, sorted) | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | e.EncodeToken(xml.EndElement{Name: node.Name}) | ||
146 | return e.Flush() | ||
147 | } | ||