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