1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package xml
6
7import (
8	"bufio"
9	"bytes"
10	"encoding"
11	"fmt"
12	"io"
13	"reflect"
14	"strconv"
15	"strings"
16)
17
18const (
19	// A generic XML header suitable for use with the output of Marshal.
20	// This is not automatically added to any output of this package,
21	// it is provided as a convenience.
22	Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
23)
24
25// Marshal returns the XML encoding of v.
26//
27// Marshal handles an array or slice by marshalling each of the elements.
28// Marshal handles a pointer by marshalling the value it points at or, if the
29// pointer is nil, by writing nothing.  Marshal handles an interface value by
30// marshalling the value it contains or, if the interface value is nil, by
31// writing nothing.  Marshal handles all other data by writing one or more XML
32// elements containing the data.
33//
34// 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 xml.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 marshalled type
40//
41// The XML element for a struct contains marshalled elements for each of the
42// 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 ",innerxml" is written verbatim, not subject
52//       to the usual marshalling procedure.
53//     - a field with tag ",comment" is written as an XML comment, not
54//       subject to the usual marshalling procedure. It must not contain
55//       the "--" string within it.
56//     - a field with a tag including the "omitempty" option is omitted
57//       if the field value is empty. The empty values are false, 0, any
58//       nil pointer or interface value, and any array, slice, map, or
59//       string of length zero.
60//     - an anonymous struct field is handled as if the fields of its
61//       value were part of the outer struct.
62//
63// If a field uses a tag "a>b>c", then the element c will be nested inside
64// parent elements a and b.  Fields that appear next to each other that name
65// the same parent will be enclosed in one XML element.
66//
67// See MarshalIndent for an example.
68//
69// Marshal will return an error if asked to marshal a channel, function, or map.
70func Marshal(v interface{}) ([]byte, error) {
71	var b bytes.Buffer
72	if err := NewEncoder(&b).Encode(v); err != nil {
73		return nil, err
74	}
75	return b.Bytes(), nil
76}
77
78// Marshaler is the interface implemented by objects that can marshal
79// themselves into valid XML elements.
80//
81// MarshalXML encodes the receiver as zero or more XML elements.
82// By convention, arrays or slices are typically encoded as a sequence
83// of elements, one per entry.
84// Using start as the element tag is not required, but doing so
85// will enable Unmarshal to match the XML elements to the correct
86// struct field.
87// One common implementation strategy is to construct a separate
88// value with a layout corresponding to the desired XML and then
89// to encode it using e.EncodeElement.
90// Another common strategy is to use repeated calls to e.EncodeToken
91// to generate the XML output one token at a time.
92// The sequence of encoded tokens must make up zero or more valid
93// XML elements.
94type Marshaler interface {
95	MarshalXML(e *Encoder, start StartElement) error
96}
97
98// MarshalerAttr is the interface implemented by objects that can marshal
99// themselves into valid XML attributes.
100//
101// MarshalXMLAttr returns an XML attribute with the encoded value of the receiver.
102// Using name as the attribute name is not required, but doing so
103// will enable Unmarshal to match the attribute to the correct
104// struct field.
105// If MarshalXMLAttr returns the zero attribute Attr{}, no attribute
106// will be generated in the output.
107// MarshalXMLAttr is used only for struct fields with the
108// "attr" option in the field tag.
109type MarshalerAttr interface {
110	MarshalXMLAttr(name Name) (Attr, error)
111}
112
113// MarshalIndent works like Marshal, but each XML element begins on a new
114// indented line that starts with prefix and is followed by one or more
115// copies of indent according to the nesting depth.
116func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
117	var b bytes.Buffer
118	enc := NewEncoder(&b)
119	enc.Indent(prefix, indent)
120	if err := enc.Encode(v); err != nil {
121		return nil, err
122	}
123	return b.Bytes(), nil
124}
125
126// An Encoder writes XML data to an output stream.
127type Encoder struct {
128	p printer
129}
130
131// NewEncoder returns a new encoder that writes to w.
132func NewEncoder(w io.Writer) *Encoder {
133	e := &Encoder{printer{Writer: bufio.NewWriter(w)}}
134	e.p.encoder = e
135	return e
136}
137
138// Indent sets the encoder to generate XML in which each element
139// begins on a new indented line that starts with prefix and is followed by
140// one or more copies of indent according to the nesting depth.
141func (enc *Encoder) Indent(prefix, indent string) {
142	enc.p.prefix = prefix
143	enc.p.indent = indent
144}
145
146// Encode writes the XML encoding of v to the stream.
147//
148// See the documentation for Marshal for details about the conversion
149// of Go values to XML.
150//
151// Encode calls Flush before returning.
152func (enc *Encoder) Encode(v interface{}) error {
153	err := enc.p.marshalValue(reflect.ValueOf(v), nil, nil)
154	if err != nil {
155		return err
156	}
157	return enc.p.Flush()
158}
159
160// EncodeElement writes the XML encoding of v to the stream,
161// using start as the outermost tag in the encoding.
162//
163// See the documentation for Marshal for details about the conversion
164// of Go values to XML.
165//
166// EncodeElement calls Flush before returning.
167func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error {
168	err := enc.p.marshalValue(reflect.ValueOf(v), nil, &start)
169	if err != nil {
170		return err
171	}
172	return enc.p.Flush()
173}
174
175var (
176	endComment   = []byte("-->")
177	endProcInst  = []byte("?>")
178	endDirective = []byte(">")
179)
180
181// EncodeToken writes the given XML token to the stream.
182// It returns an error if StartElement and EndElement tokens are not properly matched.
183//
184// EncodeToken does not call Flush, because usually it is part of a larger operation
185// such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
186// during those), and those will call Flush when finished.
187//
188// Callers that create an Encoder and then invoke EncodeToken directly, without
189// using Encode or EncodeElement, need to call Flush when finished to ensure
190// that the XML is written to the underlying writer.
191func (enc *Encoder) EncodeToken(t Token) error {
192	p := &enc.p
193	switch t := t.(type) {
194	case StartElement:
195		if err := p.writeStart(&t); err != nil {
196			return err
197		}
198	case EndElement:
199		if err := p.writeEnd(t.Name); err != nil {
200			return err
201		}
202	case CharData:
203		EscapeText(p, t)
204	case Comment:
205		if bytes.Contains(t, endComment) {
206			return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
207		}
208		p.WriteString("<!--")
209		p.Write(t)
210		p.WriteString("-->")
211		return p.cachedWriteError()
212	case ProcInst:
213		if t.Target == "xml" || !isNameString(t.Target) {
214			return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
215		}
216		if bytes.Contains(t.Inst, endProcInst) {
217			return fmt.Errorf("xml: EncodeToken of ProcInst containing ?> marker")
218		}
219		p.WriteString("<?")
220		p.WriteString(t.Target)
221		if len(t.Inst) > 0 {
222			p.WriteByte(' ')
223			p.Write(t.Inst)
224		}
225		p.WriteString("?>")
226	case Directive:
227		if bytes.Contains(t, endDirective) {
228			return fmt.Errorf("xml: EncodeToken of Directive containing > marker")
229		}
230		p.WriteString("<!")
231		p.Write(t)
232		p.WriteString(">")
233	}
234	return p.cachedWriteError()
235}
236
237// Flush flushes any buffered XML to the underlying writer.
238// See the EncodeToken documentation for details about when it is necessary.
239func (enc *Encoder) Flush() error {
240	return enc.p.Flush()
241}
242
243type printer struct {
244	*bufio.Writer
245	encoder    *Encoder
246	seq        int
247	indent     string
248	prefix     string
249	depth      int
250	indentedIn bool
251	putNewline bool
252	attrNS     map[string]string // map prefix -> name space
253	attrPrefix map[string]string // map name space -> prefix
254	prefixes   []string
255	tags       []Name
256}
257
258// createAttrPrefix finds the name space prefix attribute to use for the given name space,
259// defining a new prefix if necessary. It returns the prefix.
260func (p *printer) createAttrPrefix(url string) string {
261	if prefix := p.attrPrefix[url]; prefix != "" {
262		return prefix
263	}
264
265	// The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml"
266	// and must be referred to that way.
267	// (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns",
268	// but users should not be trying to use that one directly - that's our job.)
269	if url == xmlURL {
270		return "xml"
271	}
272
273	// Need to define a new name space.
274	if p.attrPrefix == nil {
275		p.attrPrefix = make(map[string]string)
276		p.attrNS = make(map[string]string)
277	}
278
279	// Pick a name. We try to use the final element of the path
280	// but fall back to _.
281	prefix := strings.TrimRight(url, "/")
282	if i := strings.LastIndex(prefix, "/"); i >= 0 {
283		prefix = prefix[i+1:]
284	}
285	if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
286		prefix = "_"
287	}
288	if strings.HasPrefix(prefix, "xml") {
289		// xmlanything is reserved.
290		prefix = "_" + prefix
291	}
292	if p.attrNS[prefix] != "" {
293		// Name is taken. Find a better one.
294		for p.seq++; ; p.seq++ {
295			if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" {
296				prefix = id
297				break
298			}
299		}
300	}
301
302	p.attrPrefix[url] = prefix
303	p.attrNS[prefix] = url
304
305	p.WriteString(`xmlns:`)
306	p.WriteString(prefix)
307	p.WriteString(`="`)
308	EscapeText(p, []byte(url))
309	p.WriteString(`" `)
310
311	p.prefixes = append(p.prefixes, prefix)
312
313	return prefix
314}
315
316// deleteAttrPrefix removes an attribute name space prefix.
317func (p *printer) deleteAttrPrefix(prefix string) {
318	delete(p.attrPrefix, p.attrNS[prefix])
319	delete(p.attrNS, prefix)
320}
321
322func (p *printer) markPrefix() {
323	p.prefixes = append(p.prefixes, "")
324}
325
326func (p *printer) popPrefix() {
327	for len(p.prefixes) > 0 {
328		prefix := p.prefixes[len(p.prefixes)-1]
329		p.prefixes = p.prefixes[:len(p.prefixes)-1]
330		if prefix == "" {
331			break
332		}
333		p.deleteAttrPrefix(prefix)
334	}
335}
336
337var (
338	marshalerType     = reflect.TypeOf((*Marshaler)(nil)).Elem()
339	marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem()
340	textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
341)
342
343// marshalValue writes one or more XML elements representing val.
344// If val was obtained from a struct field, finfo must have its details.
345func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error {
346	if startTemplate != nil && startTemplate.Name.Local == "" {
347		return fmt.Errorf("xml: EncodeElement of StartElement with missing name")
348	}
349
350	if !val.IsValid() {
351		return nil
352	}
353	if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) {
354		return nil
355	}
356
357	// Drill into interfaces and pointers.
358	// This can turn into an infinite loop given a cyclic chain,
359	// but it matches the Go 1 behavior.
360	for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
361		if val.IsNil() {
362			return nil
363		}
364		val = val.Elem()
365	}
366
367	kind := val.Kind()
368	typ := val.Type()
369
370	// Check for marshaler.
371	if val.CanInterface() && typ.Implements(marshalerType) {
372		return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate))
373	}
374	if val.CanAddr() {
375		pv := val.Addr()
376		if pv.CanInterface() && pv.Type().Implements(marshalerType) {
377			return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate))
378		}
379	}
380
381	// Check for text marshaler.
382	if val.CanInterface() && typ.Implements(textMarshalerType) {
383		return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), defaultStart(typ, finfo, startTemplate))
384	}
385	if val.CanAddr() {
386		pv := val.Addr()
387		if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
388			return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), defaultStart(pv.Type(), finfo, startTemplate))
389		}
390	}
391
392	// Slices and arrays iterate over the elements. They do not have an enclosing tag.
393	if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
394		for i, n := 0, val.Len(); i < n; i++ {
395			if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil {
396				return err
397			}
398		}
399		return nil
400	}
401
402	tinfo, err := getTypeInfo(typ)
403	if err != nil {
404		return err
405	}
406
407	// Create start element.
408	// Precedence for the XML element name is:
409	// 0. startTemplate
410	// 1. XMLName field in underlying struct;
411	// 2. field name/tag in the struct field; and
412	// 3. type name
413	var start StartElement
414
415	if startTemplate != nil {
416		start.Name = startTemplate.Name
417		start.Attr = append(start.Attr, startTemplate.Attr...)
418	} else if tinfo.xmlname != nil {
419		xmlname := tinfo.xmlname
420		if xmlname.name != "" {
421			start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
422		} else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" {
423			start.Name = v
424		}
425	}
426	if start.Name.Local == "" && finfo != nil {
427		start.Name.Space, start.Name.Local = finfo.xmlns, finfo.name
428	}
429	if start.Name.Local == "" {
430		name := typ.Name()
431		if name == "" {
432			return &UnsupportedTypeError{typ}
433		}
434		start.Name.Local = name
435	}
436
437	// Attributes
438	for i := range tinfo.fields {
439		finfo := &tinfo.fields[i]
440		if finfo.flags&fAttr == 0 {
441			continue
442		}
443		fv := finfo.value(val)
444		name := Name{Space: finfo.xmlns, Local: finfo.name}
445
446		if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
447			continue
448		}
449
450		if fv.Kind() == reflect.Interface && fv.IsNil() {
451			continue
452		}
453
454		if fv.CanInterface() && fv.Type().Implements(marshalerAttrType) {
455			attr, err := fv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
456			if err != nil {
457				return err
458			}
459			if attr.Name.Local != "" {
460				start.Attr = append(start.Attr, attr)
461			}
462			continue
463		}
464
465		if fv.CanAddr() {
466			pv := fv.Addr()
467			if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
468				attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
469				if err != nil {
470					return err
471				}
472				if attr.Name.Local != "" {
473					start.Attr = append(start.Attr, attr)
474				}
475				continue
476			}
477		}
478
479		if fv.CanInterface() && fv.Type().Implements(textMarshalerType) {
480			text, err := fv.Interface().(encoding.TextMarshaler).MarshalText()
481			if err != nil {
482				return err
483			}
484			start.Attr = append(start.Attr, Attr{name, string(text)})
485			continue
486		}
487
488		if fv.CanAddr() {
489			pv := fv.Addr()
490			if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
491				text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
492				if err != nil {
493					return err
494				}
495				start.Attr = append(start.Attr, Attr{name, string(text)})
496				continue
497			}
498		}
499
500		// Dereference or skip nil pointer, interface values.
501		switch fv.Kind() {
502		case reflect.Ptr, reflect.Interface:
503			if fv.IsNil() {
504				continue
505			}
506			fv = fv.Elem()
507		}
508
509		s, b, err := p.marshalSimple(fv.Type(), fv)
510		if err != nil {
511			return err
512		}
513		if b != nil {
514			s = string(b)
515		}
516		start.Attr = append(start.Attr, Attr{name, s})
517	}
518
519	if err := p.writeStart(&start); err != nil {
520		return err
521	}
522
523	if val.Kind() == reflect.Struct {
524		err = p.marshalStruct(tinfo, val)
525	} else {
526		s, b, err1 := p.marshalSimple(typ, val)
527		if err1 != nil {
528			err = err1
529		} else if b != nil {
530			EscapeText(p, b)
531		} else {
532			p.EscapeString(s)
533		}
534	}
535	if err != nil {
536		return err
537	}
538
539	if err := p.writeEnd(start.Name); err != nil {
540		return err
541	}
542
543	return p.cachedWriteError()
544}
545
546// defaultStart returns the default start element to use,
547// given the reflect type, field info, and start template.
548func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
549	var start StartElement
550	// Precedence for the XML element name is as above,
551	// except that we do not look inside structs for the first field.
552	if startTemplate != nil {
553		start.Name = startTemplate.Name
554		start.Attr = append(start.Attr, startTemplate.Attr...)
555	} else if finfo != nil && finfo.name != "" {
556		start.Name.Local = finfo.name
557		start.Name.Space = finfo.xmlns
558	} else if typ.Name() != "" {
559		start.Name.Local = typ.Name()
560	} else {
561		// Must be a pointer to a named type,
562		// since it has the Marshaler methods.
563		start.Name.Local = typ.Elem().Name()
564	}
565	return start
566}
567
568// marshalInterface marshals a Marshaler interface value.
569func (p *printer) marshalInterface(val Marshaler, start StartElement) error {
570	// Push a marker onto the tag stack so that MarshalXML
571	// cannot close the XML tags that it did not open.
572	p.tags = append(p.tags, Name{})
573	n := len(p.tags)
574
575	err := val.MarshalXML(p.encoder, start)
576	if err != nil {
577		return err
578	}
579
580	// Make sure MarshalXML closed all its tags. p.tags[n-1] is the mark.
581	if len(p.tags) > n {
582		return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local)
583	}
584	p.tags = p.tags[:n-1]
585	return nil
586}
587
588// marshalTextInterface marshals a TextMarshaler interface value.
589func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error {
590	if err := p.writeStart(&start); err != nil {
591		return err
592	}
593	text, err := val.MarshalText()
594	if err != nil {
595		return err
596	}
597	EscapeText(p, text)
598	return p.writeEnd(start.Name)
599}
600
601// writeStart writes the given start element.
602func (p *printer) writeStart(start *StartElement) error {
603	if start.Name.Local == "" {
604		return fmt.Errorf("xml: start tag with no name")
605	}
606
607	p.tags = append(p.tags, start.Name)
608	p.markPrefix()
609
610	p.writeIndent(1)
611	p.WriteByte('<')
612	p.WriteString(start.Name.Local)
613
614	if start.Name.Space != "" {
615		p.WriteString(` xmlns="`)
616		p.EscapeString(start.Name.Space)
617		p.WriteByte('"')
618	}
619
620	// Attributes
621	for _, attr := range start.Attr {
622		name := attr.Name
623		if name.Local == "" {
624			continue
625		}
626		p.WriteByte(' ')
627		if name.Space != "" {
628			p.WriteString(p.createAttrPrefix(name.Space))
629			p.WriteByte(':')
630		}
631		p.WriteString(name.Local)
632		p.WriteString(`="`)
633		p.EscapeString(attr.Value)
634		p.WriteByte('"')
635	}
636	p.WriteByte('>')
637	return nil
638}
639
640func (p *printer) writeEnd(name Name) error {
641	if name.Local == "" {
642		return fmt.Errorf("xml: end tag with no name")
643	}
644	if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" {
645		return fmt.Errorf("xml: end tag </%s> without start tag", name.Local)
646	}
647	if top := p.tags[len(p.tags)-1]; top != name {
648		if top.Local != name.Local {
649			return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local)
650		}
651		return fmt.Errorf("xml: end tag </%s> in namespace %s does not match start tag <%s> in namespace %s", name.Local, name.Space, top.Local, top.Space)
652	}
653	p.tags = p.tags[:len(p.tags)-1]
654
655	p.writeIndent(-1)
656	p.WriteByte('<')
657	p.WriteByte('/')
658	p.WriteString(name.Local)
659	p.WriteByte('>')
660	p.popPrefix()
661	return nil
662}
663
664func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) {
665	switch val.Kind() {
666	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
667		return strconv.FormatInt(val.Int(), 10), nil, nil
668	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
669		return strconv.FormatUint(val.Uint(), 10), nil, nil
670	case reflect.Float32, reflect.Float64:
671		return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil
672	case reflect.String:
673		return val.String(), nil, nil
674	case reflect.Bool:
675		return strconv.FormatBool(val.Bool()), nil, nil
676	case reflect.Array:
677		if typ.Elem().Kind() != reflect.Uint8 {
678			break
679		}
680		// [...]byte
681		var bytes []byte
682		if val.CanAddr() {
683			bytes = val.Slice(0, val.Len()).Bytes()
684		} else {
685			bytes = make([]byte, val.Len())
686			reflect.Copy(reflect.ValueOf(bytes), val)
687		}
688		return "", bytes, nil
689	case reflect.Slice:
690		if typ.Elem().Kind() != reflect.Uint8 {
691			break
692		}
693		// []byte
694		return "", val.Bytes(), nil
695	}
696	return "", nil, &UnsupportedTypeError{typ}
697}
698
699var ddBytes = []byte("--")
700
701func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
702	s := parentStack{p: p}
703	for i := range tinfo.fields {
704		finfo := &tinfo.fields[i]
705		if finfo.flags&fAttr != 0 {
706			continue
707		}
708		vf := finfo.value(val)
709
710		// Dereference or skip nil pointer, interface values.
711		switch vf.Kind() {
712		case reflect.Ptr, reflect.Interface:
713			if !vf.IsNil() {
714				vf = vf.Elem()
715			}
716		}
717
718		switch finfo.flags & fMode {
719		case fCharData:
720			if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
721				data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
722				if err != nil {
723					return err
724				}
725				Escape(p, data)
726				continue
727			}
728			if vf.CanAddr() {
729				pv := vf.Addr()
730				if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
731					data, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
732					if err != nil {
733						return err
734					}
735					Escape(p, data)
736					continue
737				}
738			}
739			var scratch [64]byte
740			switch vf.Kind() {
741			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
742				Escape(p, strconv.AppendInt(scratch[:0], vf.Int(), 10))
743			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
744				Escape(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10))
745			case reflect.Float32, reflect.Float64:
746				Escape(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits()))
747			case reflect.Bool:
748				Escape(p, strconv.AppendBool(scratch[:0], vf.Bool()))
749			case reflect.String:
750				if err := EscapeText(p, []byte(vf.String())); err != nil {
751					return err
752				}
753			case reflect.Slice:
754				if elem, ok := vf.Interface().([]byte); ok {
755					if err := EscapeText(p, elem); err != nil {
756						return err
757					}
758				}
759			}
760			continue
761
762		case fComment:
763			k := vf.Kind()
764			if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
765				return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
766			}
767			if vf.Len() == 0 {
768				continue
769			}
770			p.writeIndent(0)
771			p.WriteString("<!--")
772			dashDash := false
773			dashLast := false
774			switch k {
775			case reflect.String:
776				s := vf.String()
777				dashDash = strings.Index(s, "--") >= 0
778				dashLast = s[len(s)-1] == '-'
779				if !dashDash {
780					p.WriteString(s)
781				}
782			case reflect.Slice:
783				b := vf.Bytes()
784				dashDash = bytes.Index(b, ddBytes) >= 0
785				dashLast = b[len(b)-1] == '-'
786				if !dashDash {
787					p.Write(b)
788				}
789			default:
790				panic("can't happen")
791			}
792			if dashDash {
793				return fmt.Errorf(`xml: comments must not contain "--"`)
794			}
795			if dashLast {
796				// "--->" is invalid grammar. Make it "- -->"
797				p.WriteByte(' ')
798			}
799			p.WriteString("-->")
800			continue
801
802		case fInnerXml:
803			iface := vf.Interface()
804			switch raw := iface.(type) {
805			case []byte:
806				p.Write(raw)
807				continue
808			case string:
809				p.WriteString(raw)
810				continue
811			}
812
813		case fElement, fElement | fAny:
814			if err := s.trim(finfo.parents); err != nil {
815				return err
816			}
817			if len(finfo.parents) > len(s.stack) {
818				if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
819					if err := s.push(finfo.parents[len(s.stack):]); err != nil {
820						return err
821					}
822				}
823			}
824		}
825		if err := p.marshalValue(vf, finfo, nil); err != nil {
826			return err
827		}
828	}
829	s.trim(nil)
830	return p.cachedWriteError()
831}
832
833// return the bufio Writer's cached write error
834func (p *printer) cachedWriteError() error {
835	_, err := p.Write(nil)
836	return err
837}
838
839func (p *printer) writeIndent(depthDelta int) {
840	if len(p.prefix) == 0 && len(p.indent) == 0 {
841		return
842	}
843	if depthDelta < 0 {
844		p.depth--
845		if p.indentedIn {
846			p.indentedIn = false
847			return
848		}
849		p.indentedIn = false
850	}
851	if p.putNewline {
852		p.WriteByte('\n')
853	} else {
854		p.putNewline = true
855	}
856	if len(p.prefix) > 0 {
857		p.WriteString(p.prefix)
858	}
859	if len(p.indent) > 0 {
860		for i := 0; i < p.depth; i++ {
861			p.WriteString(p.indent)
862		}
863	}
864	if depthDelta > 0 {
865		p.depth++
866		p.indentedIn = true
867	}
868}
869
870type parentStack struct {
871	p     *printer
872	stack []string
873}
874
875// trim updates the XML context to match the longest common prefix of the stack
876// and the given parents.  A closing tag will be written for every parent
877// popped.  Passing a zero slice or nil will close all the elements.
878func (s *parentStack) trim(parents []string) error {
879	split := 0
880	for ; split < len(parents) && split < len(s.stack); split++ {
881		if parents[split] != s.stack[split] {
882			break
883		}
884	}
885	for i := len(s.stack) - 1; i >= split; i-- {
886		if err := s.p.writeEnd(Name{Local: s.stack[i]}); err != nil {
887			return err
888		}
889	}
890	s.stack = parents[:split]
891	return nil
892}
893
894// push adds parent elements to the stack and writes open tags.
895func (s *parentStack) push(parents []string) error {
896	for i := 0; i < len(parents); i++ {
897		if err := s.p.writeStart(&StartElement{Name: Name{Local: parents[i]}}); err != nil {
898			return err
899		}
900	}
901	s.stack = append(s.stack, parents...)
902	return nil
903}
904
905// A MarshalXMLError is returned when Marshal encounters a type
906// that cannot be converted into XML.
907type UnsupportedTypeError struct {
908	Type reflect.Type
909}
910
911func (e *UnsupportedTypeError) Error() string {
912	return "xml: unsupported type: " + e.Type.String()
913}
914
915func isEmptyValue(v reflect.Value) bool {
916	switch v.Kind() {
917	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
918		return v.Len() == 0
919	case reflect.Bool:
920		return !v.Bool()
921	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
922		return v.Int() == 0
923	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
924		return v.Uint() == 0
925	case reflect.Float32, reflect.Float64:
926		return v.Float() == 0
927	case reflect.Interface, reflect.Ptr:
928		return v.IsNil()
929	}
930	return false
931}
932