]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil/xml_to_struct.go
deps: github.com/hashicorp/terraform@sdk-v0.11-with-go-modules
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / private / protocol / xml / xmlutil / xml_to_struct.go
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 child.parent = n
33 if _, ok := n.Children[child.Name.Local]; !ok {
34 n.Children[child.Name.Local] = []*XMLNode{}
35 }
36 n.Children[child.Name.Local] = append(n.Children[child.Name.Local], child)
37 }
38
39 // XMLToStruct converts a xml.Decoder stream to XMLNode with nested values.
40 func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) {
41 out := &XMLNode{}
42 for {
43 tok, err := d.Token()
44 if err != nil {
45 if err == io.EOF {
46 break
47 } else {
48 return out, err
49 }
50 }
51
52 if tok == nil {
53 break
54 }
55
56 switch typed := tok.(type) {
57 case xml.CharData:
58 out.Text = string(typed.Copy())
59 case xml.StartElement:
60 el := typed.Copy()
61 out.Attr = el.Attr
62 if out.Children == nil {
63 out.Children = map[string][]*XMLNode{}
64 }
65
66 name := typed.Name.Local
67 slice := out.Children[name]
68 if slice == nil {
69 slice = []*XMLNode{}
70 }
71 node, e := XMLToStruct(d, &el)
72 out.findNamespaces()
73 if e != nil {
74 return out, e
75 }
76 node.Name = typed.Name
77 node.findNamespaces()
78 tempOut := *out
79 // Save into a temp variable, simply because out gets squashed during
80 // loop iterations
81 node.parent = &tempOut
82 slice = append(slice, node)
83 out.Children[name] = slice
84 case xml.EndElement:
85 if s != nil && s.Name.Local == typed.Name.Local { // matching end token
86 return out, nil
87 }
88 out = &XMLNode{}
89 }
90 }
91 return out, nil
92 }
93
94 func (n *XMLNode) findNamespaces() {
95 ns := map[string]string{}
96 for _, a := range n.Attr {
97 if a.Name.Space == "xmlns" {
98 ns[a.Value] = a.Name.Local
99 }
100 }
101
102 n.namespaces = ns
103 }
104
105 func (n *XMLNode) findElem(name string) (string, bool) {
106 for node := n; node != nil; node = node.parent {
107 for _, a := range node.Attr {
108 namespace := a.Name.Space
109 if v, ok := node.namespaces[namespace]; ok {
110 namespace = v
111 }
112 if name == fmt.Sprintf("%s:%s", namespace, a.Name.Local) {
113 return a.Value, true
114 }
115 }
116 }
117 return "", false
118 }
119
120 // StructToXML writes an XMLNode to a xml.Encoder as tokens.
121 func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error {
122 e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr})
123
124 if node.Text != "" {
125 e.EncodeToken(xml.CharData([]byte(node.Text)))
126 } else if sorted {
127 sortedNames := []string{}
128 for k := range node.Children {
129 sortedNames = append(sortedNames, k)
130 }
131 sort.Strings(sortedNames)
132
133 for _, k := range sortedNames {
134 for _, v := range node.Children[k] {
135 StructToXML(e, v, sorted)
136 }
137 }
138 } else {
139 for _, c := range node.Children {
140 for _, v := range c {
141 StructToXML(e, v, sorted)
142 }
143 }
144 }
145
146 e.EncodeToken(xml.EndElement{Name: node.Name})
147 return e.Flush()
148 }