1 package xml
2
3 import (
4 "encoding/base64"
5 "fmt"
6 "math/big"
7 "strconv"
8
9 "github.com/aws/smithy-go/encoding"
10 )
11
12
13
14 type Value struct {
15 w writer
16 scratch *[]byte
17
18
19 startElement StartElement
20
21
22 isFlattened bool
23 }
24
25
26 func newFlattenedValue(w writer, scratch *[]byte, startElement StartElement) Value {
27 return Value{
28 w: w,
29 scratch: scratch,
30 startElement: startElement,
31 }
32 }
33
34
35 func newValue(w writer, scratch *[]byte, startElement StartElement) Value {
36 writeStartElement(w, startElement)
37 return Value{w: w, scratch: scratch, startElement: startElement}
38 }
39
40
41
42 func writeStartElement(w writer, el StartElement) error {
43 if el.isZero() {
44 return fmt.Errorf("xml start element cannot be nil")
45 }
46
47 w.WriteRune(leftAngleBracket)
48
49 if len(el.Name.Space) != 0 {
50 escapeString(w, el.Name.Space)
51 w.WriteRune(colon)
52 }
53 escapeString(w, el.Name.Local)
54 for _, attr := range el.Attr {
55 w.WriteRune(' ')
56 writeAttribute(w, &attr)
57 }
58
59 w.WriteRune(rightAngleBracket)
60 return nil
61 }
62
63
64
65
66 func writeAttribute(w writer, attr *Attr) {
67
68 if len(attr.Name.Space) != 0 && len(attr.Name.Local) != 0 {
69 escapeString(w, attr.Name.Space)
70 w.WriteRune(colon)
71 }
72
73
74 if len(attr.Name.Local) == 0 {
75 attr.Name.Local = attr.Name.Space
76 }
77
78 escapeString(w, attr.Name.Local)
79 w.WriteRune(equals)
80 w.WriteRune(quote)
81 escapeString(w, attr.Value)
82 w.WriteRune(quote)
83 }
84
85
86 func writeEndElement(w writer, el EndElement) error {
87 if el.isZero() {
88 return fmt.Errorf("xml end element cannot be nil")
89 }
90
91 w.WriteRune(leftAngleBracket)
92 w.WriteRune(forwardSlash)
93
94 if len(el.Name.Space) != 0 {
95 escapeString(w, el.Name.Space)
96 w.WriteRune(colon)
97 }
98 escapeString(w, el.Name.Local)
99 w.WriteRune(rightAngleBracket)
100
101 return nil
102 }
103
104
105
106 func (xv Value) String(v string) {
107 escapeString(xv.w, v)
108 xv.Close()
109 }
110
111
112
113 func (xv Value) Byte(v int8) {
114 xv.Long(int64(v))
115 }
116
117
118
119 func (xv Value) Short(v int16) {
120 xv.Long(int64(v))
121 }
122
123
124
125 func (xv Value) Integer(v int32) {
126 xv.Long(int64(v))
127 }
128
129
130
131 func (xv Value) Long(v int64) {
132 *xv.scratch = strconv.AppendInt((*xv.scratch)[:0], v, 10)
133 xv.w.Write(*xv.scratch)
134
135 xv.Close()
136 }
137
138
139
140 func (xv Value) Float(v float32) {
141 xv.float(float64(v), 32)
142 xv.Close()
143 }
144
145
146
147 func (xv Value) Double(v float64) {
148 xv.float(v, 64)
149 xv.Close()
150 }
151
152 func (xv Value) float(v float64, bits int) {
153 *xv.scratch = encoding.EncodeFloat((*xv.scratch)[:0], v, bits)
154 xv.w.Write(*xv.scratch)
155 }
156
157
158
159 func (xv Value) Boolean(v bool) {
160 *xv.scratch = strconv.AppendBool((*xv.scratch)[:0], v)
161 xv.w.Write(*xv.scratch)
162
163 xv.Close()
164 }
165
166
167
168 func (xv Value) Base64EncodeBytes(v []byte) {
169 encodeByteSlice(xv.w, (*xv.scratch)[:0], v)
170 xv.Close()
171 }
172
173
174
175 func (xv Value) BigInteger(v *big.Int) {
176 xv.w.Write([]byte(v.Text(10)))
177 xv.Close()
178 }
179
180
181
182 func (xv Value) BigDecimal(v *big.Float) {
183 if i, accuracy := v.Int64(); accuracy == big.Exact {
184 xv.Long(i)
185 return
186 }
187
188 xv.w.Write([]byte(v.Text('e', -1)))
189 xv.Close()
190 }
191
192
193
194
195 func (xv Value) Write(v []byte, escapeXMLText bool) {
196
197 if escapeXMLText {
198 escapeText(xv.w, v)
199 } else {
200
201 xv.w.Write(v)
202 }
203
204 xv.Close()
205 }
206
207
208
209
210
211
212 func (xv Value) MemberElement(element StartElement) Value {
213 return newValue(xv.w, xv.scratch, element)
214 }
215
216
217
218
219
220
221
222
223 func (xv Value) FlattenedElement(element StartElement) Value {
224 v := newFlattenedValue(xv.w, xv.scratch, element)
225 v.isFlattened = true
226 return v
227 }
228
229
230
231
232
233 func (xv Value) Array() *Array {
234 return newArray(xv.w, xv.scratch, arrayMemberWrapper, xv.startElement, xv.isFlattened)
235 }
236
237
244 func (xv Value) ArrayWithCustomName(element StartElement) *Array {
245 return newArray(xv.w, xv.scratch, element, xv.startElement, xv.isFlattened)
246 }
247
248
255 func (xv Value) Map() *Map {
256
257 if xv.isFlattened {
258 return newFlattenedMap(xv.w, xv.scratch, xv.startElement)
259 }
260
261
262 return newMap(xv.w, xv.scratch)
263 }
264
265
266
267 func encodeByteSlice(w writer, scratch []byte, v []byte) {
268 if v == nil {
269 return
270 }
271
272 encodedLen := base64.StdEncoding.EncodedLen(len(v))
273 if encodedLen <= len(scratch) {
274
275
276 dst := scratch[:encodedLen]
277 base64.StdEncoding.Encode(dst, v)
278 w.Write(dst)
279 } else if encodedLen <= 1024 {
280
281
282 dst := make([]byte, encodedLen)
283 base64.StdEncoding.Encode(dst, v)
284 w.Write(dst)
285 } else {
286
287
288 enc := base64.NewEncoder(base64.StdEncoding, w)
289 enc.Write(v)
290 enc.Close()
291 }
292 }
293
294
295 func (xv Value) IsFlattened() bool {
296 return xv.isFlattened
297 }
298
299
300 func (xv Value) Close() {
301 writeEndElement(xv.w, xv.startElement.End())
302 }
303
View as plain text