Skip to content

Commit 057e4af

Browse files
committed
encoding/xml: update to ydnar/go@5b16be4d9c565
1 parent e0a6901 commit 057e4af

File tree

7 files changed

+784
-296
lines changed

7 files changed

+784
-296
lines changed

marshal.go

Lines changed: 115 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
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.
141149
func 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

184192
var (
@@ -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.
299307
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()
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

338353
type 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.
924941
func 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
10901157
func (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

Comments
 (0)