88 "bufio"
99 "bytes"
1010 "encoding"
11+ "errors"
1112 "fmt"
1213 "io"
1314 "reflect"
@@ -32,39 +33,39 @@ const (
3233// elements containing the data.
3334//
3435// The name for the XML elements is taken from, in order of preference:
35- // - the tag on the XMLName field, if the data is a struct
36- // - the value of the XMLName field of type Name
37- // - the tag of the struct field used to obtain the data
38- // - the name of the struct field used to obtain the data
39- // - the name of the marshaled type
36+ // - the tag on the XMLName field, if the data is a struct
37+ // - the value of the XMLName field of type Name
38+ // - the tag of the struct field used to obtain the data
39+ // - the name of the struct field used to obtain the data
40+ // - the name of the marshaled type
4041//
4142// The XML element for a struct contains marshaled elements for each of the
4243// exported fields of the struct, with these exceptions:
43- // - the XMLName field, described above, is omitted.
44- // - a field with tag "-" is omitted.
45- // - a field with tag "name,attr" becomes an attribute with
46- // the given name in the XML element.
47- // - a field with tag ",attr" becomes an attribute with the
48- // field name in the XML element.
49- // - a field with tag ",chardata" is written as character data,
50- // not as an XML element.
51- // - a field with tag ",cdata" is written as character data
52- // wrapped in one or more <![CDATA[ ... ]]> tags, not as an XML element.
53- // - a field with tag ",innerxml" is written verbatim, not subject
54- // to the usual marshaling procedure.
55- // - a field with tag ",comment" is written as an XML comment, not
56- // subject to the usual marshaling procedure. It must not contain
57- // the "--" string within it.
58- // - a field with a tag including the "omitempty" option is omitted
59- // if the field value is empty. The empty values are false, 0, any
60- // nil pointer or interface value, and any array, slice, map, or
61- // string of length zero.
62- // - an anonymous struct field is handled as if the fields of its
63- // value were part of the outer struct.
64- // - a field implementing Marshaler is written by calling its MarshalXML
65- // method.
66- // - a field implementing encoding.TextMarshaler is written by encoding the
67- // result of its MarshalText method as text.
44+ // - the XMLName field, described above, is omitted.
45+ // - a field with tag "-" is omitted.
46+ // - a field with tag "name,attr" becomes an attribute with
47+ // the given name in the XML element.
48+ // - a field with tag ",attr" becomes an attribute with the
49+ // field name in the XML element.
50+ // - a field with tag ",chardata" is written as character data,
51+ // not as an XML element.
52+ // - a field with tag ",cdata" is written as character data
53+ // wrapped in one or more <![CDATA[ ... ]]> tags, not as an XML element.
54+ // - a field with tag ",innerxml" is written verbatim, not subject
55+ // to the usual marshaling procedure.
56+ // - a field with tag ",comment" is written as an XML comment, not
57+ // subject to the usual marshaling procedure. It must not contain
58+ // the "--" string within it.
59+ // - a field with a tag including the "omitempty" option is omitted
60+ // if the field value is empty. The empty values are false, 0, any
61+ // nil pointer or interface value, and any array, slice, map, or
62+ // string of length zero.
63+ // - an anonymous struct field is handled as if the fields of its
64+ // value were part of the outer struct.
65+ // - a field implementing Marshaler is written by calling its MarshalXML
66+ // method.
67+ // - a field implementing encoding.TextMarshaler is written by encoding the
68+ // result of its MarshalText method as text.
6869//
6970// If a field uses a tag "a>b>c", then the element c will be nested inside
7071// parent elements a and b. Fields that appear next to each other that name
@@ -76,9 +77,13 @@ const (
7677// See MarshalIndent for an example.
7778//
7879// Marshal will return an error if asked to marshal a channel, function, or map.
79- func Marshal (v interface {} ) ([]byte , error ) {
80+ func Marshal (v any ) ([]byte , error ) {
8081 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 {
8287 return nil , err
8388 }
8489 return b .Bytes (), nil
@@ -122,13 +127,16 @@ type MarshalerAttr interface {
122127// MarshalIndent works like Marshal, but each XML element begins on a new
123128// indented line that starts with prefix and is followed by one or more
124129// copies of indent according to the nesting depth.
125- func MarshalIndent (v interface {} , prefix , indent string ) ([]byte , error ) {
130+ func MarshalIndent (v any , prefix , indent string ) ([]byte , error ) {
126131 var b bytes.Buffer
127132 enc := NewEncoder (& b )
128133 enc .Indent (prefix , indent )
129134 if err := enc .Encode (v ); err != nil {
130135 return nil , err
131136 }
137+ if err := enc .Close (); err != nil {
138+ return nil , err
139+ }
132140 return b .Bytes (), nil
133141}
134142
@@ -139,7 +147,7 @@ type Encoder struct {
139147
140148// NewEncoder returns a new encoder that writes to w.
141149func NewEncoder (w io.Writer ) * Encoder {
142- e := & Encoder {printer {Writer : bufio .NewWriter (w )}}
150+ e := & Encoder {printer {w : bufio .NewWriter (w )}}
143151 e .p .encoder = e
144152 return e
145153}
@@ -158,12 +166,12 @@ func (enc *Encoder) Indent(prefix, indent string) {
158166// of Go values to XML.
159167//
160168// Encode calls Flush before returning.
161- func (enc * Encoder ) Encode (v interface {} ) error {
169+ func (enc * Encoder ) Encode (v any ) error {
162170 err := enc .p .marshalValue (reflect .ValueOf (v ), nil , nil )
163171 if err != nil {
164172 return err
165173 }
166- return enc .p .Flush ()
174+ return enc .p .w . Flush ()
167175}
168176
169177// EncodeElement writes the XML encoding of v to the stream,
@@ -173,12 +181,12 @@ func (enc *Encoder) Encode(v interface{}) error {
173181// of Go values to XML.
174182//
175183// EncodeElement calls Flush before returning.
176- func (enc * Encoder ) EncodeElement (v interface {} , start StartElement ) error {
184+ func (enc * Encoder ) EncodeElement (v any , start StartElement ) error {
177185 err := enc .p .marshalValue (reflect .ValueOf (v ), nil , & start )
178186 if err != nil {
179187 return err
180188 }
181- return enc .p .Flush ()
189+ return enc .p .w . Flush ()
182190}
183191
184192var (
@@ -224,7 +232,7 @@ func (enc *Encoder) EncodeToken(t Token) error {
224232 case ProcInst :
225233 // First token to be encoded which is also a ProcInst with target of xml
226234 // 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 {
228236 return fmt .Errorf ("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded" )
229237 }
230238 if ! isNameString (t .Target ) {
@@ -297,7 +305,14 @@ func isValidDirective(dir Directive) bool {
297305// Flush flushes any buffered XML to the underlying writer.
298306// See the EncodeToken documentation for details about when it is necessary.
299307func (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 ()
301316}
302317
303318// element represents a serialized XML element, in the form of either:
@@ -336,7 +351,7 @@ func joinPrefixed(prefix, name string) string {
336351}
337352
338353type printer struct {
339- * bufio.Writer
354+ w * bufio.Writer
340355 encoder * Encoder
341356 seq int
342357 indent string
@@ -345,6 +360,8 @@ type printer struct {
345360 indentedIn bool
346361 putNewline bool
347362 elements []element
363+ closed bool
364+ err error
348365}
349366
350367// getPrefix finds the prefix to use for the given namespace URI, but does not create it.
@@ -460,7 +477,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
460477 // Drill into interfaces and pointers.
461478 // This can turn into an infinite loop given a cyclic chain,
462479 // but it matches the Go 1 behavior.
463- for val .Kind () == reflect .Interface || val .Kind () == reflect .Ptr {
480+ for val .Kind () == reflect .Interface || val .Kind () == reflect .Pointer {
464481 if val .IsNil () {
465482 return nil
466483 }
@@ -555,7 +572,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
555572
556573 fv := finfo .value (val , dontInitNilPointers )
557574
558- if finfo .flags & fOmitEmpty != 0 && isEmptyValue (fv ) {
575+ if finfo .flags & fOmitEmpty != 0 && ( ! fv . IsValid () || isEmptyValue (fv ) ) {
559576 continue
560577 }
561578
@@ -653,7 +670,7 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value)
653670
654671 // Dereference or skip nil pointer, interface values.
655672 switch val .Kind () {
656- case reflect .Ptr , reflect .Interface :
673+ case reflect .Pointer , reflect .Interface :
657674 if val .IsNil () {
658675 return nil
659676 }
@@ -721,7 +738,7 @@ func (p *printer) marshalInterface(val Marshaler, start StartElement) error {
721738 return err
722739 }
723740
724- // Make sure MarshalXML closed all its tags. p.tags [n-1] is the mark.
741+ // Make sure MarshalXML closed all its tags. p.elements [n-1] is the mark.
725742 if len (p .elements ) > n {
726743 return fmt .Errorf ("xml: %s.MarshalXML wrote invalid XML: <%s> not closed" , receiverType (val ), p .elements [len (p .elements )- 1 ].name )
727744 }
@@ -922,7 +939,7 @@ var ddBytes = []byte("--")
922939// This can turn into an infinite loop given a cyclic chain,
923940// but it matches the Go 1 behavior.
924941func indirect (vf reflect.Value ) reflect.Value {
925- for vf .Kind () == reflect .Interface || vf .Kind () == reflect .Ptr {
942+ for vf .Kind () == reflect .Interface || vf .Kind () == reflect .Pointer {
926943 if vf .IsNil () {
927944 return vf
928945 }
@@ -1071,7 +1088,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
10711088 return err
10721089 }
10731090 if len (finfo .parents ) > len (s .stack ) {
1074- if vf .Kind () != reflect .Ptr && vf .Kind () != reflect .Interface || ! vf .IsNil () {
1091+ if vf .Kind () != reflect .Pointer && vf .Kind () != reflect .Interface || ! vf .IsNil () {
10751092 if err := s .push (finfo .parents [len (s .stack ):]); err != nil {
10761093 return err
10771094 }
@@ -1086,6 +1103,56 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
10861103 return p .cachedWriteError ()
10871104}
10881105
1106+ // Write implements io.Writer
1107+ func (p * printer ) Write (b []byte ) (n int , err error ) {
1108+ if p .closed && p .err == nil {
1109+ p .err = errors .New ("use of closed Encoder" )
1110+ }
1111+ if p .err == nil {
1112+ n , p .err = p .w .Write (b )
1113+ }
1114+ return n , p .err
1115+ }
1116+
1117+ // WriteString implements io.StringWriter
1118+ func (p * printer ) WriteString (s string ) (n int , err error ) {
1119+ if p .closed && p .err == nil {
1120+ p .err = errors .New ("use of closed Encoder" )
1121+ }
1122+ if p .err == nil {
1123+ n , p .err = p .w .WriteString (s )
1124+ }
1125+ return n , p .err
1126+ }
1127+
1128+ // WriteByte implements io.ByteWriter
1129+ func (p * printer ) WriteByte (c byte ) error {
1130+ if p .closed && p .err == nil {
1131+ p .err = errors .New ("use of closed Encoder" )
1132+ }
1133+ if p .err == nil {
1134+ p .err = p .w .WriteByte (c )
1135+ }
1136+ return p .err
1137+ }
1138+
1139+ // Close the Encoder, indicating that no more data will be written. It flushes
1140+ // any buffered XML to the underlying writer and returns an error if the
1141+ // written XML is invalid (e.g. by containing unclosed elements).
1142+ func (p * printer ) Close () error {
1143+ if p .closed {
1144+ return nil
1145+ }
1146+ p .closed = true
1147+ if err := p .w .Flush (); err != nil {
1148+ return err
1149+ }
1150+ if len (p .elements ) > 0 {
1151+ return fmt .Errorf ("unclosed tag <%s>" , p .elements [len (p .elements )- 1 ].name )
1152+ }
1153+ return nil
1154+ }
1155+
10891156// return the bufio Writer's cached write error
10901157func (p * printer ) cachedWriteError () error {
10911158 _ , err := p .Write (nil )
@@ -1180,7 +1247,7 @@ func isEmptyValue(v reflect.Value) bool {
11801247 return v .Uint () == 0
11811248 case reflect .Float32 , reflect .Float64 :
11821249 return v .Float () == 0
1183- case reflect .Interface , reflect .Ptr :
1250+ case reflect .Interface , reflect .Pointer :
11841251 return v .IsNil ()
11851252 }
11861253 return false
0 commit comments