Tizen_4.0 base
[platform/upstream/docker-engine.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         "io"
6         "sort"
7 )
8
9 // A XMLNode contains the values to be encoded or decoded.
10 type XMLNode struct {
11         Name     xml.Name              `json:",omitempty"`
12         Children map[string][]*XMLNode `json:",omitempty"`
13         Text     string                `json:",omitempty"`
14         Attr     []xml.Attr            `json:",omitempty"`
15 }
16
17 // NewXMLElement returns a pointer to a new XMLNode initialized to default values.
18 func NewXMLElement(name xml.Name) *XMLNode {
19         return &XMLNode{
20                 Name:     name,
21                 Children: map[string][]*XMLNode{},
22                 Attr:     []xml.Attr{},
23         }
24 }
25
26 // AddChild adds child to the XMLNode.
27 func (n *XMLNode) AddChild(child *XMLNode) {
28         if _, ok := n.Children[child.Name.Local]; !ok {
29                 n.Children[child.Name.Local] = []*XMLNode{}
30         }
31         n.Children[child.Name.Local] = append(n.Children[child.Name.Local], child)
32 }
33
34 // XMLToStruct converts a xml.Decoder stream to XMLNode with nested values.
35 func XMLToStruct(d *xml.Decoder, s *xml.StartElement) (*XMLNode, error) {
36         out := &XMLNode{}
37         for {
38                 tok, err := d.Token()
39                 if tok == nil || err == io.EOF {
40                         break
41                 }
42                 if err != nil {
43                         return out, err
44                 }
45
46                 switch typed := tok.(type) {
47                 case xml.CharData:
48                         out.Text = string(typed.Copy())
49                 case xml.StartElement:
50                         el := typed.Copy()
51                         out.Attr = el.Attr
52                         if out.Children == nil {
53                                 out.Children = map[string][]*XMLNode{}
54                         }
55
56                         name := typed.Name.Local
57                         slice := out.Children[name]
58                         if slice == nil {
59                                 slice = []*XMLNode{}
60                         }
61                         node, e := XMLToStruct(d, &el)
62                         if e != nil {
63                                 return out, e
64                         }
65                         node.Name = typed.Name
66                         slice = append(slice, node)
67                         out.Children[name] = slice
68                 case xml.EndElement:
69                         if s != nil && s.Name.Local == typed.Name.Local { // matching end token
70                                 return out, nil
71                         }
72                 }
73         }
74         return out, nil
75 }
76
77 // StructToXML writes an XMLNode to a xml.Encoder as tokens.
78 func StructToXML(e *xml.Encoder, node *XMLNode, sorted bool) error {
79         e.EncodeToken(xml.StartElement{Name: node.Name, Attr: node.Attr})
80
81         if node.Text != "" {
82                 e.EncodeToken(xml.CharData([]byte(node.Text)))
83         } else if sorted {
84                 sortedNames := []string{}
85                 for k := range node.Children {
86                         sortedNames = append(sortedNames, k)
87                 }
88                 sort.Strings(sortedNames)
89
90                 for _, k := range sortedNames {
91                         for _, v := range node.Children[k] {
92                                 StructToXML(e, v, sorted)
93                         }
94                 }
95         } else {
96                 for _, c := range node.Children {
97                         for _, v := range c {
98                                 StructToXML(e, v, sorted)
99                         }
100                 }
101         }
102
103         e.EncodeToken(xml.EndElement{Name: node.Name})
104         return e.Flush()
105 }