8
8
"bufio"
9
9
"bytes"
10
10
"encoding"
11
+ "errors"
11
12
"fmt"
12
13
"io"
13
14
"reflect"
@@ -78,7 +79,11 @@ const (
78
79
// Marshal will return an error if asked to marshal a channel, function, or map.
79
80
func Marshal (v any ) ([]byte , error ) {
80
81
var b bytes.Buffer
81
- if err := NewEncoder (& b ).Encode (v ); err != nil {
82
+ enc := NewEncoder (& b )
83
+ if err := enc .Encode (v ); err != nil {
84
+ return nil , err
85
+ }
86
+ if err := enc .Close (); err != nil {
82
87
return nil , err
83
88
}
84
89
return b .Bytes (), nil
@@ -129,6 +134,9 @@ func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
129
134
if err := enc .Encode (v ); err != nil {
130
135
return nil , err
131
136
}
137
+ if err := enc .Close (); err != nil {
138
+ return nil , err
139
+ }
132
140
return b .Bytes (), nil
133
141
}
134
142
@@ -139,7 +147,7 @@ type Encoder struct {
139
147
140
148
// NewEncoder returns a new encoder that writes to w.
141
149
func NewEncoder (w io.Writer ) * Encoder {
142
- e := & Encoder {printer {Writer : bufio .NewWriter (w )}}
150
+ e := & Encoder {printer {w : bufio .NewWriter (w )}}
143
151
e .p .encoder = e
144
152
return e
145
153
}
@@ -163,7 +171,7 @@ func (enc *Encoder) Encode(v any) error {
163
171
if err != nil {
164
172
return err
165
173
}
166
- return enc .p .Flush ()
174
+ return enc .p .w . Flush ()
167
175
}
168
176
169
177
// EncodeElement writes the XML encoding of v to the stream,
@@ -178,7 +186,7 @@ func (enc *Encoder) EncodeElement(v any, start StartElement) error {
178
186
if err != nil {
179
187
return err
180
188
}
181
- return enc .p .Flush ()
189
+ return enc .p .w . Flush ()
182
190
}
183
191
184
192
var (
@@ -224,7 +232,7 @@ func (enc *Encoder) EncodeToken(t Token) error {
224
232
case ProcInst :
225
233
// First token to be encoded which is also a ProcInst with target of xml
226
234
// is the xml declaration. The only ProcInst where target of xml is allowed.
227
- if t .Target == "xml" && p .Buffered () != 0 {
235
+ if t .Target == "xml" && p .w . Buffered () != 0 {
228
236
return fmt .Errorf ("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded" )
229
237
}
230
238
if ! isNameString (t .Target ) {
@@ -297,11 +305,18 @@ func isValidDirective(dir Directive) bool {
297
305
// Flush flushes any buffered XML to the underlying writer.
298
306
// See the EncodeToken documentation for details about when it is necessary.
299
307
func (enc * Encoder ) Flush () error {
300
- return enc .p .Flush ()
308
+ return enc .p .w .Flush ()
309
+ }
310
+
311
+ // Close the Encoder, indicating that no more data will be written. It flushes
312
+ // any buffered XML to the underlying writer and returns an error if the
313
+ // written XML is invalid (e.g. by containing unclosed elements).
314
+ func (enc * Encoder ) Close () error {
315
+ return enc .p .Close ()
301
316
}
302
317
303
318
type printer struct {
304
- * bufio.Writer
319
+ w * bufio.Writer
305
320
encoder * Encoder
306
321
seq int
307
322
indent string
@@ -313,6 +328,8 @@ type printer struct {
313
328
attrPrefix map [string ]string // map name space -> prefix
314
329
prefixes []string
315
330
tags []Name
331
+ closed bool
332
+ err error
316
333
}
317
334
318
335
// createAttrPrefix finds the name space prefix attribute to use for the given name space,
@@ -961,6 +978,56 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
961
978
return p .cachedWriteError ()
962
979
}
963
980
981
+ // Write implements io.Writer
982
+ func (p * printer ) Write (b []byte ) (n int , err error ) {
983
+ if p .closed && p .err == nil {
984
+ p .err = errors .New ("use of closed Encoder" )
985
+ }
986
+ if p .err == nil {
987
+ n , p .err = p .w .Write (b )
988
+ }
989
+ return n , p .err
990
+ }
991
+
992
+ // WriteString implements io.StringWriter
993
+ func (p * printer ) WriteString (s string ) (n int , err error ) {
994
+ if p .closed && p .err == nil {
995
+ p .err = errors .New ("use of closed Encoder" )
996
+ }
997
+ if p .err == nil {
998
+ n , p .err = p .w .WriteString (s )
999
+ }
1000
+ return n , p .err
1001
+ }
1002
+
1003
+ // WriteByte implements io.ByteWriter
1004
+ func (p * printer ) WriteByte (c byte ) error {
1005
+ if p .closed && p .err == nil {
1006
+ p .err = errors .New ("use of closed Encoder" )
1007
+ }
1008
+ if p .err == nil {
1009
+ p .err = p .w .WriteByte (c )
1010
+ }
1011
+ return p .err
1012
+ }
1013
+
1014
+ // Close the Encoder, indicating that no more data will be written. It flushes
1015
+ // any buffered XML to the underlying writer and returns an error if the
1016
+ // written XML is invalid (e.g. by containing unclosed elements).
1017
+ func (p * printer ) Close () error {
1018
+ if p .closed {
1019
+ return nil
1020
+ }
1021
+ p .closed = true
1022
+ if err := p .w .Flush (); err != nil {
1023
+ return err
1024
+ }
1025
+ if len (p .tags ) > 0 {
1026
+ return fmt .Errorf ("unclosed tag <%s>" , p .tags [len (p .tags )- 1 ].Local )
1027
+ }
1028
+ return nil
1029
+ }
1030
+
964
1031
// return the bufio Writer's cached write error
965
1032
func (p * printer ) cachedWriteError () error {
966
1033
_ , err := p .Write (nil )
0 commit comments