Home | History | Annotate | Download | only in xml
      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 
      5 package xml
      6 
      7 import (
      8 	"bufio"
      9 	"bytes"
     10 	"encoding"
     11 	"fmt"
     12 	"io"
     13 	"reflect"
     14 	"strconv"
     15 	"strings"
     16 )
     17 
     18 const (
     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.
     70 func 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.
     94 type 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.
    109 type 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.
    116 func 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.
    127 type Encoder struct {
    128 	p printer
    129 }
    130 
    131 // NewEncoder returns a new encoder that writes to w.
    132 func 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.
    141 func (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.
    152 func (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.
    167 func (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 
    175 var (
    176 	begComment   = []byte("<!--")
    177 	endComment   = []byte("-->")
    178 	endProcInst  = []byte("?>")
    179 	endDirective = []byte(">")
    180 )
    181 
    182 // EncodeToken writes the given XML token to the stream.
    183 // It returns an error if StartElement and EndElement tokens are not properly matched.
    184 //
    185 // EncodeToken does not call Flush, because usually it is part of a larger operation
    186 // such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
    187 // during those), and those will call Flush when finished.
    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.
    191 //
    192 // EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
    193 // in the stream.
    194 func (enc *Encoder) EncodeToken(t Token) error {
    195 
    196 	p := &enc.p
    197 	switch t := t.(type) {
    198 	case StartElement:
    199 		if err := p.writeStart(&t); err != nil {
    200 			return err
    201 		}
    202 	case EndElement:
    203 		if err := p.writeEnd(t.Name); err != nil {
    204 			return err
    205 		}
    206 	case CharData:
    207 		escapeText(p, t, false)
    208 	case Comment:
    209 		if bytes.Contains(t, endComment) {
    210 			return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
    211 		}
    212 		p.WriteString("<!--")
    213 		p.Write(t)
    214 		p.WriteString("-->")
    215 		return p.cachedWriteError()
    216 	case ProcInst:
    217 		// First token to be encoded which is also a ProcInst with target of xml
    218 		// is the xml declaration.  The only ProcInst where target of xml is allowed.
    219 		if t.Target == "xml" && p.Buffered() != 0 {
    220 			return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
    221 		}
    222 		if !isNameString(t.Target) {
    223 			return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
    224 		}
    225 		if bytes.Contains(t.Inst, endProcInst) {
    226 			return fmt.Errorf("xml: EncodeToken of ProcInst containing ?> marker")
    227 		}
    228 		p.WriteString("<?")
    229 		p.WriteString(t.Target)
    230 		if len(t.Inst) > 0 {
    231 			p.WriteByte(' ')
    232 			p.Write(t.Inst)
    233 		}
    234 		p.WriteString("?>")
    235 	case Directive:
    236 		if !isValidDirective(t) {
    237 			return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers")
    238 		}
    239 		p.WriteString("<!")
    240 		p.Write(t)
    241 		p.WriteString(">")
    242 	default:
    243 		return fmt.Errorf("xml: EncodeToken of invalid token type")
    244 
    245 	}
    246 	return p.cachedWriteError()
    247 }
    248 
    249 // isValidDirective reports whether dir is a valid directive text,
    250 // meaning angle brackets are matched, ignoring comments and strings.
    251 func isValidDirective(dir Directive) bool {
    252 	var (
    253 		depth     int
    254 		inquote   uint8
    255 		incomment bool
    256 	)
    257 	for i, c := range dir {
    258 		switch {
    259 		case incomment:
    260 			if c == '>' {
    261 				if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) {
    262 					incomment = false
    263 				}
    264 			}
    265 			// Just ignore anything in comment
    266 		case inquote != 0:
    267 			if c == inquote {
    268 				inquote = 0
    269 			}
    270 			// Just ignore anything within quotes
    271 		case c == '\'' || c == '"':
    272 			inquote = c
    273 		case c == '<':
    274 			if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) {
    275 				incomment = true
    276 			} else {
    277 				depth++
    278 			}
    279 		case c == '>':
    280 			if depth == 0 {
    281 				return false
    282 			}
    283 			depth--
    284 		}
    285 	}
    286 	return depth == 0 && inquote == 0 && !incomment
    287 }
    288 
    289 // Flush flushes any buffered XML to the underlying writer.
    290 // See the EncodeToken documentation for details about when it is necessary.
    291 func (enc *Encoder) Flush() error {
    292 	return enc.p.Flush()
    293 }
    294 
    295 type printer struct {
    296 	*bufio.Writer
    297 	encoder    *Encoder
    298 	seq        int
    299 	indent     string
    300 	prefix     string
    301 	depth      int
    302 	indentedIn bool
    303 	putNewline bool
    304 	attrNS     map[string]string // map prefix -> name space
    305 	attrPrefix map[string]string // map name space -> prefix
    306 	prefixes   []string
    307 	tags       []Name
    308 }
    309 
    310 // createAttrPrefix finds the name space prefix attribute to use for the given name space,
    311 // defining a new prefix if necessary. It returns the prefix.
    312 func (p *printer) createAttrPrefix(url string) string {
    313 	if prefix := p.attrPrefix[url]; prefix != "" {
    314 		return prefix
    315 	}
    316 
    317 	// The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml"
    318 	// and must be referred to that way.
    319 	// (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns",
    320 	// but users should not be trying to use that one directly - that's our job.)
    321 	if url == xmlURL {
    322 		return "xml"
    323 	}
    324 
    325 	// Need to define a new name space.
    326 	if p.attrPrefix == nil {
    327 		p.attrPrefix = make(map[string]string)
    328 		p.attrNS = make(map[string]string)
    329 	}
    330 
    331 	// Pick a name. We try to use the final element of the path
    332 	// but fall back to _.
    333 	prefix := strings.TrimRight(url, "/")
    334 	if i := strings.LastIndex(prefix, "/"); i >= 0 {
    335 		prefix = prefix[i+1:]
    336 	}
    337 	if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
    338 		prefix = "_"
    339 	}
    340 	if strings.HasPrefix(prefix, "xml") {
    341 		// xmlanything is reserved.
    342 		prefix = "_" + prefix
    343 	}
    344 	if p.attrNS[prefix] != "" {
    345 		// Name is taken. Find a better one.
    346 		for p.seq++; ; p.seq++ {
    347 			if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" {
    348 				prefix = id
    349 				break
    350 			}
    351 		}
    352 	}
    353 
    354 	p.attrPrefix[url] = prefix
    355 	p.attrNS[prefix] = url
    356 
    357 	p.WriteString(`xmlns:`)
    358 	p.WriteString(prefix)
    359 	p.WriteString(`="`)
    360 	EscapeText(p, []byte(url))
    361 	p.WriteString(`" `)
    362 
    363 	p.prefixes = append(p.prefixes, prefix)
    364 
    365 	return prefix
    366 }
    367 
    368 // deleteAttrPrefix removes an attribute name space prefix.
    369 func (p *printer) deleteAttrPrefix(prefix string) {
    370 	delete(p.attrPrefix, p.attrNS[prefix])
    371 	delete(p.attrNS, prefix)
    372 }
    373 
    374 func (p *printer) markPrefix() {
    375 	p.prefixes = append(p.prefixes, "")
    376 }
    377 
    378 func (p *printer) popPrefix() {
    379 	for len(p.prefixes) > 0 {
    380 		prefix := p.prefixes[len(p.prefixes)-1]
    381 		p.prefixes = p.prefixes[:len(p.prefixes)-1]
    382 		if prefix == "" {
    383 			break
    384 		}
    385 		p.deleteAttrPrefix(prefix)
    386 	}
    387 }
    388 
    389 var (
    390 	marshalerType     = reflect.TypeOf((*Marshaler)(nil)).Elem()
    391 	marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem()
    392 	textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
    393 )
    394 
    395 // marshalValue writes one or more XML elements representing val.
    396 // If val was obtained from a struct field, finfo must have its details.
    397 func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error {
    398 	if startTemplate != nil && startTemplate.Name.Local == "" {
    399 		return fmt.Errorf("xml: EncodeElement of StartElement with missing name")
    400 	}
    401 
    402 	if !val.IsValid() {
    403 		return nil
    404 	}
    405 	if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) {
    406 		return nil
    407 	}
    408 
    409 	// Drill into interfaces and pointers.
    410 	// This can turn into an infinite loop given a cyclic chain,
    411 	// but it matches the Go 1 behavior.
    412 	for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr {
    413 		if val.IsNil() {
    414 			return nil
    415 		}
    416 		val = val.Elem()
    417 	}
    418 
    419 	kind := val.Kind()
    420 	typ := val.Type()
    421 
    422 	// Check for marshaler.
    423 	if val.CanInterface() && typ.Implements(marshalerType) {
    424 		return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate))
    425 	}
    426 	if val.CanAddr() {
    427 		pv := val.Addr()
    428 		if pv.CanInterface() && pv.Type().Implements(marshalerType) {
    429 			return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate))
    430 		}
    431 	}
    432 
    433 	// Check for text marshaler.
    434 	if val.CanInterface() && typ.Implements(textMarshalerType) {
    435 		return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), defaultStart(typ, finfo, startTemplate))
    436 	}
    437 	if val.CanAddr() {
    438 		pv := val.Addr()
    439 		if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
    440 			return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), defaultStart(pv.Type(), finfo, startTemplate))
    441 		}
    442 	}
    443 
    444 	// Slices and arrays iterate over the elements. They do not have an enclosing tag.
    445 	if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
    446 		for i, n := 0, val.Len(); i < n; i++ {
    447 			if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil {
    448 				return err
    449 			}
    450 		}
    451 		return nil
    452 	}
    453 
    454 	tinfo, err := getTypeInfo(typ)
    455 	if err != nil {
    456 		return err
    457 	}
    458 
    459 	// Create start element.
    460 	// Precedence for the XML element name is:
    461 	// 0. startTemplate
    462 	// 1. XMLName field in underlying struct;
    463 	// 2. field name/tag in the struct field; and
    464 	// 3. type name
    465 	var start StartElement
    466 
    467 	if startTemplate != nil {
    468 		start.Name = startTemplate.Name
    469 		start.Attr = append(start.Attr, startTemplate.Attr...)
    470 	} else if tinfo.xmlname != nil {
    471 		xmlname := tinfo.xmlname
    472 		if xmlname.name != "" {
    473 			start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
    474 		} else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" {
    475 			start.Name = v
    476 		}
    477 	}
    478 	if start.Name.Local == "" && finfo != nil {
    479 		start.Name.Space, start.Name.Local = finfo.xmlns, finfo.name
    480 	}
    481 	if start.Name.Local == "" {
    482 		name := typ.Name()
    483 		if name == "" {
    484 			return &UnsupportedTypeError{typ}
    485 		}
    486 		start.Name.Local = name
    487 	}
    488 
    489 	// Attributes
    490 	for i := range tinfo.fields {
    491 		finfo := &tinfo.fields[i]
    492 		if finfo.flags&fAttr == 0 {
    493 			continue
    494 		}
    495 		fv := finfo.value(val)
    496 		name := Name{Space: finfo.xmlns, Local: finfo.name}
    497 
    498 		if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
    499 			continue
    500 		}
    501 
    502 		if fv.Kind() == reflect.Interface && fv.IsNil() {
    503 			continue
    504 		}
    505 
    506 		if fv.CanInterface() && fv.Type().Implements(marshalerAttrType) {
    507 			attr, err := fv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
    508 			if err != nil {
    509 				return err
    510 			}
    511 			if attr.Name.Local != "" {
    512 				start.Attr = append(start.Attr, attr)
    513 			}
    514 			continue
    515 		}
    516 
    517 		if fv.CanAddr() {
    518 			pv := fv.Addr()
    519 			if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
    520 				attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
    521 				if err != nil {
    522 					return err
    523 				}
    524 				if attr.Name.Local != "" {
    525 					start.Attr = append(start.Attr, attr)
    526 				}
    527 				continue
    528 			}
    529 		}
    530 
    531 		if fv.CanInterface() && fv.Type().Implements(textMarshalerType) {
    532 			text, err := fv.Interface().(encoding.TextMarshaler).MarshalText()
    533 			if err != nil {
    534 				return err
    535 			}
    536 			start.Attr = append(start.Attr, Attr{name, string(text)})
    537 			continue
    538 		}
    539 
    540 		if fv.CanAddr() {
    541 			pv := fv.Addr()
    542 			if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
    543 				text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
    544 				if err != nil {
    545 					return err
    546 				}
    547 				start.Attr = append(start.Attr, Attr{name, string(text)})
    548 				continue
    549 			}
    550 		}
    551 
    552 		// Dereference or skip nil pointer, interface values.
    553 		switch fv.Kind() {
    554 		case reflect.Ptr, reflect.Interface:
    555 			if fv.IsNil() {
    556 				continue
    557 			}
    558 			fv = fv.Elem()
    559 		}
    560 
    561 		s, b, err := p.marshalSimple(fv.Type(), fv)
    562 		if err != nil {
    563 			return err
    564 		}
    565 		if b != nil {
    566 			s = string(b)
    567 		}
    568 		start.Attr = append(start.Attr, Attr{name, s})
    569 	}
    570 
    571 	if err := p.writeStart(&start); err != nil {
    572 		return err
    573 	}
    574 
    575 	if val.Kind() == reflect.Struct {
    576 		err = p.marshalStruct(tinfo, val)
    577 	} else {
    578 		s, b, err1 := p.marshalSimple(typ, val)
    579 		if err1 != nil {
    580 			err = err1
    581 		} else if b != nil {
    582 			EscapeText(p, b)
    583 		} else {
    584 			p.EscapeString(s)
    585 		}
    586 	}
    587 	if err != nil {
    588 		return err
    589 	}
    590 
    591 	if err := p.writeEnd(start.Name); err != nil {
    592 		return err
    593 	}
    594 
    595 	return p.cachedWriteError()
    596 }
    597 
    598 // defaultStart returns the default start element to use,
    599 // given the reflect type, field info, and start template.
    600 func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
    601 	var start StartElement
    602 	// Precedence for the XML element name is as above,
    603 	// except that we do not look inside structs for the first field.
    604 	if startTemplate != nil {
    605 		start.Name = startTemplate.Name
    606 		start.Attr = append(start.Attr, startTemplate.Attr...)
    607 	} else if finfo != nil && finfo.name != "" {
    608 		start.Name.Local = finfo.name
    609 		start.Name.Space = finfo.xmlns
    610 	} else if typ.Name() != "" {
    611 		start.Name.Local = typ.Name()
    612 	} else {
    613 		// Must be a pointer to a named type,
    614 		// since it has the Marshaler methods.
    615 		start.Name.Local = typ.Elem().Name()
    616 	}
    617 	return start
    618 }
    619 
    620 // marshalInterface marshals a Marshaler interface value.
    621 func (p *printer) marshalInterface(val Marshaler, start StartElement) error {
    622 	// Push a marker onto the tag stack so that MarshalXML
    623 	// cannot close the XML tags that it did not open.
    624 	p.tags = append(p.tags, Name{})
    625 	n := len(p.tags)
    626 
    627 	err := val.MarshalXML(p.encoder, start)
    628 	if err != nil {
    629 		return err
    630 	}
    631 
    632 	// Make sure MarshalXML closed all its tags. p.tags[n-1] is the mark.
    633 	if len(p.tags) > n {
    634 		return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local)
    635 	}
    636 	p.tags = p.tags[:n-1]
    637 	return nil
    638 }
    639 
    640 // marshalTextInterface marshals a TextMarshaler interface value.
    641 func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error {
    642 	if err := p.writeStart(&start); err != nil {
    643 		return err
    644 	}
    645 	text, err := val.MarshalText()
    646 	if err != nil {
    647 		return err
    648 	}
    649 	EscapeText(p, text)
    650 	return p.writeEnd(start.Name)
    651 }
    652 
    653 // writeStart writes the given start element.
    654 func (p *printer) writeStart(start *StartElement) error {
    655 	if start.Name.Local == "" {
    656 		return fmt.Errorf("xml: start tag with no name")
    657 	}
    658 
    659 	p.tags = append(p.tags, start.Name)
    660 	p.markPrefix()
    661 
    662 	p.writeIndent(1)
    663 	p.WriteByte('<')
    664 	p.WriteString(start.Name.Local)
    665 
    666 	if start.Name.Space != "" {
    667 		p.WriteString(` xmlns="`)
    668 		p.EscapeString(start.Name.Space)
    669 		p.WriteByte('"')
    670 	}
    671 
    672 	// Attributes
    673 	for _, attr := range start.Attr {
    674 		name := attr.Name
    675 		if name.Local == "" {
    676 			continue
    677 		}
    678 		p.WriteByte(' ')
    679 		if name.Space != "" {
    680 			p.WriteString(p.createAttrPrefix(name.Space))
    681 			p.WriteByte(':')
    682 		}
    683 		p.WriteString(name.Local)
    684 		p.WriteString(`="`)
    685 		p.EscapeString(attr.Value)
    686 		p.WriteByte('"')
    687 	}
    688 	p.WriteByte('>')
    689 	return nil
    690 }
    691 
    692 func (p *printer) writeEnd(name Name) error {
    693 	if name.Local == "" {
    694 		return fmt.Errorf("xml: end tag with no name")
    695 	}
    696 	if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" {
    697 		return fmt.Errorf("xml: end tag </%s> without start tag", name.Local)
    698 	}
    699 	if top := p.tags[len(p.tags)-1]; top != name {
    700 		if top.Local != name.Local {
    701 			return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local)
    702 		}
    703 		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)
    704 	}
    705 	p.tags = p.tags[:len(p.tags)-1]
    706 
    707 	p.writeIndent(-1)
    708 	p.WriteByte('<')
    709 	p.WriteByte('/')
    710 	p.WriteString(name.Local)
    711 	p.WriteByte('>')
    712 	p.popPrefix()
    713 	return nil
    714 }
    715 
    716 func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) {
    717 	switch val.Kind() {
    718 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    719 		return strconv.FormatInt(val.Int(), 10), nil, nil
    720 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    721 		return strconv.FormatUint(val.Uint(), 10), nil, nil
    722 	case reflect.Float32, reflect.Float64:
    723 		return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil
    724 	case reflect.String:
    725 		return val.String(), nil, nil
    726 	case reflect.Bool:
    727 		return strconv.FormatBool(val.Bool()), nil, nil
    728 	case reflect.Array:
    729 		if typ.Elem().Kind() != reflect.Uint8 {
    730 			break
    731 		}
    732 		// [...]byte
    733 		var bytes []byte
    734 		if val.CanAddr() {
    735 			bytes = val.Slice(0, val.Len()).Bytes()
    736 		} else {
    737 			bytes = make([]byte, val.Len())
    738 			reflect.Copy(reflect.ValueOf(bytes), val)
    739 		}
    740 		return "", bytes, nil
    741 	case reflect.Slice:
    742 		if typ.Elem().Kind() != reflect.Uint8 {
    743 			break
    744 		}
    745 		// []byte
    746 		return "", val.Bytes(), nil
    747 	}
    748 	return "", nil, &UnsupportedTypeError{typ}
    749 }
    750 
    751 var ddBytes = []byte("--")
    752 
    753 func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
    754 	s := parentStack{p: p}
    755 	for i := range tinfo.fields {
    756 		finfo := &tinfo.fields[i]
    757 		if finfo.flags&fAttr != 0 {
    758 			continue
    759 		}
    760 		vf := finfo.value(val)
    761 
    762 		// Dereference or skip nil pointer, interface values.
    763 		switch vf.Kind() {
    764 		case reflect.Ptr, reflect.Interface:
    765 			if !vf.IsNil() {
    766 				vf = vf.Elem()
    767 			}
    768 		}
    769 
    770 		switch finfo.flags & fMode {
    771 		case fCharData:
    772 			if err := s.trim(finfo.parents); err != nil {
    773 				return err
    774 			}
    775 			if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
    776 				data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
    777 				if err != nil {
    778 					return err
    779 				}
    780 				Escape(p, data)
    781 				continue
    782 			}
    783 			if vf.CanAddr() {
    784 				pv := vf.Addr()
    785 				if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
    786 					data, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
    787 					if err != nil {
    788 						return err
    789 					}
    790 					Escape(p, data)
    791 					continue
    792 				}
    793 			}
    794 			var scratch [64]byte
    795 			switch vf.Kind() {
    796 			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    797 				Escape(p, strconv.AppendInt(scratch[:0], vf.Int(), 10))
    798 			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    799 				Escape(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10))
    800 			case reflect.Float32, reflect.Float64:
    801 				Escape(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits()))
    802 			case reflect.Bool:
    803 				Escape(p, strconv.AppendBool(scratch[:0], vf.Bool()))
    804 			case reflect.String:
    805 				if err := EscapeText(p, []byte(vf.String())); err != nil {
    806 					return err
    807 				}
    808 			case reflect.Slice:
    809 				if elem, ok := vf.Interface().([]byte); ok {
    810 					if err := EscapeText(p, elem); err != nil {
    811 						return err
    812 					}
    813 				}
    814 			}
    815 			continue
    816 
    817 		case fComment:
    818 			if err := s.trim(finfo.parents); err != nil {
    819 				return err
    820 			}
    821 			k := vf.Kind()
    822 			if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
    823 				return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
    824 			}
    825 			if vf.Len() == 0 {
    826 				continue
    827 			}
    828 			p.writeIndent(0)
    829 			p.WriteString("<!--")
    830 			dashDash := false
    831 			dashLast := false
    832 			switch k {
    833 			case reflect.String:
    834 				s := vf.String()
    835 				dashDash = strings.Index(s, "--") >= 0
    836 				dashLast = s[len(s)-1] == '-'
    837 				if !dashDash {
    838 					p.WriteString(s)
    839 				}
    840 			case reflect.Slice:
    841 				b := vf.Bytes()
    842 				dashDash = bytes.Index(b, ddBytes) >= 0
    843 				dashLast = b[len(b)-1] == '-'
    844 				if !dashDash {
    845 					p.Write(b)
    846 				}
    847 			default:
    848 				panic("can't happen")
    849 			}
    850 			if dashDash {
    851 				return fmt.Errorf(`xml: comments must not contain "--"`)
    852 			}
    853 			if dashLast {
    854 				// "--->" is invalid grammar. Make it "- -->"
    855 				p.WriteByte(' ')
    856 			}
    857 			p.WriteString("-->")
    858 			continue
    859 
    860 		case fInnerXml:
    861 			iface := vf.Interface()
    862 			switch raw := iface.(type) {
    863 			case []byte:
    864 				p.Write(raw)
    865 				continue
    866 			case string:
    867 				p.WriteString(raw)
    868 				continue
    869 			}
    870 
    871 		case fElement, fElement | fAny:
    872 			if err := s.trim(finfo.parents); err != nil {
    873 				return err
    874 			}
    875 			if len(finfo.parents) > len(s.stack) {
    876 				if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
    877 					if err := s.push(finfo.parents[len(s.stack):]); err != nil {
    878 						return err
    879 					}
    880 				}
    881 			}
    882 		}
    883 		if err := p.marshalValue(vf, finfo, nil); err != nil {
    884 			return err
    885 		}
    886 	}
    887 	s.trim(nil)
    888 	return p.cachedWriteError()
    889 }
    890 
    891 // return the bufio Writer's cached write error
    892 func (p *printer) cachedWriteError() error {
    893 	_, err := p.Write(nil)
    894 	return err
    895 }
    896 
    897 func (p *printer) writeIndent(depthDelta int) {
    898 	if len(p.prefix) == 0 && len(p.indent) == 0 {
    899 		return
    900 	}
    901 	if depthDelta < 0 {
    902 		p.depth--
    903 		if p.indentedIn {
    904 			p.indentedIn = false
    905 			return
    906 		}
    907 		p.indentedIn = false
    908 	}
    909 	if p.putNewline {
    910 		p.WriteByte('\n')
    911 	} else {
    912 		p.putNewline = true
    913 	}
    914 	if len(p.prefix) > 0 {
    915 		p.WriteString(p.prefix)
    916 	}
    917 	if len(p.indent) > 0 {
    918 		for i := 0; i < p.depth; i++ {
    919 			p.WriteString(p.indent)
    920 		}
    921 	}
    922 	if depthDelta > 0 {
    923 		p.depth++
    924 		p.indentedIn = true
    925 	}
    926 }
    927 
    928 type parentStack struct {
    929 	p     *printer
    930 	stack []string
    931 }
    932 
    933 // trim updates the XML context to match the longest common prefix of the stack
    934 // and the given parents.  A closing tag will be written for every parent
    935 // popped.  Passing a zero slice or nil will close all the elements.
    936 func (s *parentStack) trim(parents []string) error {
    937 	split := 0
    938 	for ; split < len(parents) && split < len(s.stack); split++ {
    939 		if parents[split] != s.stack[split] {
    940 			break
    941 		}
    942 	}
    943 	for i := len(s.stack) - 1; i >= split; i-- {
    944 		if err := s.p.writeEnd(Name{Local: s.stack[i]}); err != nil {
    945 			return err
    946 		}
    947 	}
    948 	s.stack = s.stack[:split]
    949 	return nil
    950 }
    951 
    952 // push adds parent elements to the stack and writes open tags.
    953 func (s *parentStack) push(parents []string) error {
    954 	for i := 0; i < len(parents); i++ {
    955 		if err := s.p.writeStart(&StartElement{Name: Name{Local: parents[i]}}); err != nil {
    956 			return err
    957 		}
    958 	}
    959 	s.stack = append(s.stack, parents...)
    960 	return nil
    961 }
    962 
    963 // A MarshalXMLError is returned when Marshal encounters a type
    964 // that cannot be converted into XML.
    965 type UnsupportedTypeError struct {
    966 	Type reflect.Type
    967 }
    968 
    969 func (e *UnsupportedTypeError) Error() string {
    970 	return "xml: unsupported type: " + e.Type.String()
    971 }
    972 
    973 func isEmptyValue(v reflect.Value) bool {
    974 	switch v.Kind() {
    975 	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
    976 		return v.Len() == 0
    977 	case reflect.Bool:
    978 		return !v.Bool()
    979 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    980 		return v.Int() == 0
    981 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    982 		return v.Uint() == 0
    983 	case reflect.Float32, reflect.Float64:
    984 		return v.Float() == 0
    985 	case reflect.Interface, reflect.Ptr:
    986 		return v.IsNil()
    987 	}
    988 	return false
    989 }
    990