rsc.io/go@v0.0.0-20150416155037-e040fd465409/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 // 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 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 183 // properly matched. 184 // 185 // EncodeToken does not call Flush, because usually it is part of a 186 // larger operation such as Encode or EncodeElement (or a custom 187 // Marshaler's MarshalXML invoked during those), and those will call 188 // Flush when finished. Callers that create an Encoder and then invoke 189 // EncodeToken directly, without using Encode or EncodeElement, need to 190 // call Flush when finished to ensure that the XML is written to the 191 // underlying writer. 192 // 193 // EncodeToken allows writing a ProcInst with Target set to "xml" only 194 // as the first token in the stream. 195 // 196 // When encoding a StartElement holding an XML namespace prefix 197 // declaration for a prefix that is not already declared, contained 198 // elements (including the StartElement itself) will use the declared 199 // prefix when encoding names with matching namespace URIs. 200 func (enc *Encoder) EncodeToken(t Token) error { 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) 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 bytes.Contains(t, endDirective) { 242 return fmt.Errorf("xml: EncodeToken of Directive containing > marker") 243 } 244 p.WriteString("<!") 245 p.Write(t) 246 p.WriteString(">") 247 } 248 return p.cachedWriteError() 249 } 250 251 // Flush flushes any buffered XML to the underlying writer. 252 // See the EncodeToken documentation for details about when it is necessary. 253 func (enc *Encoder) Flush() error { 254 return enc.p.Flush() 255 } 256 257 type printer struct { 258 *bufio.Writer 259 encoder *Encoder 260 seq int 261 indent string 262 prefix string 263 depth int 264 indentedIn bool 265 putNewline bool 266 defaultNS string 267 attrNS map[string]string // map prefix -> name space 268 attrPrefix map[string]string // map name space -> prefix 269 prefixes []printerPrefix 270 tags []Name 271 } 272 273 // printerPrefix holds a namespace undo record. 274 // When an element is popped, the prefix record 275 // is set back to the recorded URL. The empty 276 // prefix records the URL for the default name space. 277 // 278 // The start of an element is recorded with an element 279 // that has mark=true. 280 type printerPrefix struct { 281 prefix string 282 url string 283 mark bool 284 } 285 286 func (p *printer) prefixForNS(url string, isAttr bool) string { 287 // The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml" 288 // and must be referred to that way. 289 // (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns", 290 // but users should not be trying to use that one directly - that's our job.) 291 if url == xmlURL { 292 return "xml" 293 } 294 if !isAttr && url == p.defaultNS { 295 // We can use the default name space. 296 return "" 297 } 298 return p.attrPrefix[url] 299 } 300 301 // defineNS pushes any namespace definition found in the given attribute. 302 // If ignoreNonEmptyDefault is true, an xmlns="nonempty" 303 // attribute will be ignored. 304 func (p *printer) defineNS(attr Attr, ignoreNonEmptyDefault bool) error { 305 var prefix string 306 if attr.Name.Local == "xmlns" { 307 if attr.Name.Space != "" && attr.Name.Space != "xml" && attr.Name.Space != xmlURL { 308 return fmt.Errorf("xml: cannot redefine xmlns attribute prefix") 309 } 310 } else if attr.Name.Space == "xmlns" && attr.Name.Local != "" { 311 prefix = attr.Name.Local 312 if attr.Value == "" { 313 // Technically, an empty XML namespace is allowed for an attribute. 314 // From http://www.w3.org/TR/xml-names11/#scoping-defaulting: 315 // 316 // The attribute value in a namespace declaration for a prefix may be 317 // empty. This has the effect, within the scope of the declaration, of removing 318 // any association of the prefix with a namespace name. 319 // 320 // However our namespace prefixes here are used only as hints. There's 321 // no need to respect the removal of a namespace prefix, so we ignore it. 322 return nil 323 } 324 } else { 325 // Ignore: it's not a namespace definition 326 return nil 327 } 328 if prefix == "" { 329 if attr.Value == p.defaultNS { 330 // No need for redefinition. 331 return nil 332 } 333 if attr.Value != "" && ignoreNonEmptyDefault { 334 // We have an xmlns="..." value but 335 // it can't define a name space in this context, 336 // probably because the element has an empty 337 // name space. In this case, we just ignore 338 // the name space declaration. 339 return nil 340 } 341 } else if _, ok := p.attrPrefix[attr.Value]; ok { 342 // There's already a prefix for the given name space, 343 // so use that. This prevents us from 344 // having two prefixes for the same name space 345 // so attrNS and attrPrefix can remain bijective. 346 return nil 347 } 348 p.pushPrefix(prefix, attr.Value) 349 return nil 350 } 351 352 // createNSPrefix creates a name space prefix attribute 353 // to use for the given name space, defining a new prefix 354 // if necessary. 355 // If isAttr is true, the prefix is to be created for an attribute 356 // prefix, which means that the default name space cannot 357 // be used. 358 func (p *printer) createNSPrefix(url string, isAttr bool) { 359 if _, ok := p.attrPrefix[url]; ok { 360 // We already have a prefix for the given URL. 361 return 362 } 363 switch { 364 case !isAttr && url == p.defaultNS: 365 // We can use the default name space. 366 return 367 case url == "": 368 // The only way we can encode names in the empty 369 // name space is by using the default name space, 370 // so we must use that. 371 if p.defaultNS != "" { 372 // The default namespace is non-empty, so we 373 // need to set it to empty. 374 p.pushPrefix("", "") 375 } 376 return 377 case url == xmlURL: 378 return 379 } 380 // TODO If the URL is an existing prefix, we could 381 // use it as is. That would enable the 382 // marshaling of elements that had been unmarshaled 383 // and with a name space prefix that was not found. 384 // although technically it would be incorrect. 385 386 // Pick a name. We try to use the final element of the path 387 // but fall back to _. 388 prefix := strings.TrimRight(url, "/") 389 if i := strings.LastIndex(prefix, "/"); i >= 0 { 390 prefix = prefix[i+1:] 391 } 392 if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") { 393 prefix = "_" 394 } 395 if strings.HasPrefix(prefix, "xml") { 396 // xmlanything is reserved. 397 prefix = "_" + prefix 398 } 399 if p.attrNS[prefix] != "" { 400 // Name is taken. Find a better one. 401 for p.seq++; ; p.seq++ { 402 if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" { 403 prefix = id 404 break 405 } 406 } 407 } 408 409 p.pushPrefix(prefix, url) 410 } 411 412 // writeNamespaces writes xmlns attributes for all the 413 // namespace prefixes that have been defined in 414 // the current element. 415 func (p *printer) writeNamespaces() { 416 for i := len(p.prefixes) - 1; i >= 0; i-- { 417 prefix := p.prefixes[i] 418 if prefix.mark { 419 return 420 } 421 p.WriteString(" ") 422 if prefix.prefix == "" { 423 // Default name space. 424 p.WriteString(`xmlns="`) 425 } else { 426 p.WriteString("xmlns:") 427 p.WriteString(prefix.prefix) 428 p.WriteString(`="`) 429 } 430 EscapeText(p, []byte(p.nsForPrefix(prefix.prefix))) 431 p.WriteString(`"`) 432 } 433 } 434 435 // pushPrefix pushes a new prefix on the prefix stack 436 // without checking to see if it is already defined. 437 func (p *printer) pushPrefix(prefix, url string) { 438 p.prefixes = append(p.prefixes, printerPrefix{ 439 prefix: prefix, 440 url: p.nsForPrefix(prefix), 441 }) 442 p.setAttrPrefix(prefix, url) 443 } 444 445 // nsForPrefix returns the name space for the given 446 // prefix. Note that this is not valid for the 447 // empty attribute prefix, which always has an empty 448 // name space. 449 func (p *printer) nsForPrefix(prefix string) string { 450 if prefix == "" { 451 return p.defaultNS 452 } 453 return p.attrNS[prefix] 454 } 455 456 // markPrefix marks the start of an element on the prefix 457 // stack. 458 func (p *printer) markPrefix() { 459 p.prefixes = append(p.prefixes, printerPrefix{ 460 mark: true, 461 }) 462 } 463 464 // popPrefix pops all defined prefixes for the current 465 // element. 466 func (p *printer) popPrefix() { 467 for len(p.prefixes) > 0 { 468 prefix := p.prefixes[len(p.prefixes)-1] 469 p.prefixes = p.prefixes[:len(p.prefixes)-1] 470 if prefix.mark { 471 break 472 } 473 p.setAttrPrefix(prefix.prefix, prefix.url) 474 } 475 } 476 477 // setAttrPrefix sets an attribute name space prefix. 478 // If url is empty, the attribute is removed. 479 // If prefix is empty, the default name space is set. 480 func (p *printer) setAttrPrefix(prefix, url string) { 481 if prefix == "" { 482 p.defaultNS = url 483 return 484 } 485 if url == "" { 486 delete(p.attrPrefix, p.attrNS[prefix]) 487 delete(p.attrNS, prefix) 488 return 489 } 490 if p.attrPrefix == nil { 491 // Need to define a new name space. 492 p.attrPrefix = make(map[string]string) 493 p.attrNS = make(map[string]string) 494 } 495 // Remove any old prefix value. This is OK because we maintain a 496 // strict one-to-one mapping between prefix and URL (see 497 // defineNS) 498 delete(p.attrPrefix, p.attrNS[prefix]) 499 p.attrPrefix[url] = prefix 500 p.attrNS[prefix] = url 501 } 502 503 var ( 504 marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() 505 marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem() 506 textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() 507 ) 508 509 // marshalValue writes one or more XML elements representing val. 510 // If val was obtained from a struct field, finfo must have its details. 511 func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error { 512 if startTemplate != nil && startTemplate.Name.Local == "" { 513 return fmt.Errorf("xml: EncodeElement of StartElement with missing name") 514 } 515 516 if !val.IsValid() { 517 return nil 518 } 519 if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) { 520 return nil 521 } 522 523 // Drill into interfaces and pointers. 524 // This can turn into an infinite loop given a cyclic chain, 525 // but it matches the Go 1 behavior. 526 for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr { 527 if val.IsNil() { 528 return nil 529 } 530 val = val.Elem() 531 } 532 533 kind := val.Kind() 534 typ := val.Type() 535 536 // Check for marshaler. 537 if val.CanInterface() && typ.Implements(marshalerType) { 538 return p.marshalInterface(val.Interface().(Marshaler), p.defaultStart(typ, finfo, startTemplate)) 539 } 540 if val.CanAddr() { 541 pv := val.Addr() 542 if pv.CanInterface() && pv.Type().Implements(marshalerType) { 543 return p.marshalInterface(pv.Interface().(Marshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) 544 } 545 } 546 547 // Check for text marshaler. 548 if val.CanInterface() && typ.Implements(textMarshalerType) { 549 return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), p.defaultStart(typ, finfo, startTemplate)) 550 } 551 if val.CanAddr() { 552 pv := val.Addr() 553 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { 554 return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) 555 } 556 } 557 558 // Slices and arrays iterate over the elements. They do not have an enclosing tag. 559 if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 { 560 for i, n := 0, val.Len(); i < n; i++ { 561 if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil { 562 return err 563 } 564 } 565 return nil 566 } 567 568 tinfo, err := getTypeInfo(typ) 569 if err != nil { 570 return err 571 } 572 573 // Create start element. 574 // Precedence for the XML element name is: 575 // 0. startTemplate 576 // 1. XMLName field in underlying struct; 577 // 2. field name/tag in the struct field; and 578 // 3. type name 579 var start StartElement 580 581 // Historic behaviour: elements use the default name space 582 // they are contained in by default. 583 start.Name.Space = p.defaultNS 584 585 if startTemplate != nil { 586 start.Name = startTemplate.Name 587 start.Attr = append(start.Attr, startTemplate.Attr...) 588 } else if tinfo.xmlname != nil { 589 xmlname := tinfo.xmlname 590 if xmlname.name != "" { 591 start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name 592 } else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" { 593 start.Name = v 594 } 595 } 596 if start.Name.Local == "" && finfo != nil { 597 start.Name.Local = finfo.name 598 if finfo.xmlns != "" { 599 start.Name.Space = finfo.xmlns 600 } 601 } 602 if start.Name.Local == "" { 603 name := typ.Name() 604 if name == "" { 605 return &UnsupportedTypeError{typ} 606 } 607 start.Name.Local = name 608 } 609 // Historic behaviour: an element that's in a namespace sets 610 // the default namespace for all elements contained within it. 611 start.setDefaultNamespace() 612 613 // Attributes 614 for i := range tinfo.fields { 615 finfo := &tinfo.fields[i] 616 if finfo.flags&fAttr == 0 { 617 continue 618 } 619 fv := finfo.value(val) 620 name := Name{Space: finfo.xmlns, Local: finfo.name} 621 622 if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) { 623 continue 624 } 625 626 if fv.Kind() == reflect.Interface && fv.IsNil() { 627 continue 628 } 629 630 if fv.CanInterface() && fv.Type().Implements(marshalerAttrType) { 631 attr, err := fv.Interface().(MarshalerAttr).MarshalXMLAttr(name) 632 if err != nil { 633 return err 634 } 635 if attr.Name.Local != "" { 636 start.Attr = append(start.Attr, attr) 637 } 638 continue 639 } 640 641 if fv.CanAddr() { 642 pv := fv.Addr() 643 if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) { 644 attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name) 645 if err != nil { 646 return err 647 } 648 if attr.Name.Local != "" { 649 start.Attr = append(start.Attr, attr) 650 } 651 continue 652 } 653 } 654 655 if fv.CanInterface() && fv.Type().Implements(textMarshalerType) { 656 text, err := fv.Interface().(encoding.TextMarshaler).MarshalText() 657 if err != nil { 658 return err 659 } 660 start.Attr = append(start.Attr, Attr{name, string(text)}) 661 continue 662 } 663 664 if fv.CanAddr() { 665 pv := fv.Addr() 666 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { 667 text, err := pv.Interface().(encoding.TextMarshaler).MarshalText() 668 if err != nil { 669 return err 670 } 671 start.Attr = append(start.Attr, Attr{name, string(text)}) 672 continue 673 } 674 } 675 676 // Dereference or skip nil pointer, interface values. 677 switch fv.Kind() { 678 case reflect.Ptr, reflect.Interface: 679 if fv.IsNil() { 680 continue 681 } 682 fv = fv.Elem() 683 } 684 685 s, b, err := p.marshalSimple(fv.Type(), fv) 686 if err != nil { 687 return err 688 } 689 if b != nil { 690 s = string(b) 691 } 692 start.Attr = append(start.Attr, Attr{name, s}) 693 } 694 695 if err := p.writeStart(&start); err != nil { 696 return err 697 } 698 699 if val.Kind() == reflect.Struct { 700 err = p.marshalStruct(tinfo, val) 701 } else { 702 s, b, err1 := p.marshalSimple(typ, val) 703 if err1 != nil { 704 err = err1 705 } else if b != nil { 706 EscapeText(p, b) 707 } else { 708 p.EscapeString(s) 709 } 710 } 711 if err != nil { 712 return err 713 } 714 715 if err := p.writeEnd(start.Name); err != nil { 716 return err 717 } 718 719 return p.cachedWriteError() 720 } 721 722 // defaultStart returns the default start element to use, 723 // given the reflect type, field info, and start template. 724 func (p *printer) defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement { 725 var start StartElement 726 // Precedence for the XML element name is as above, 727 // except that we do not look inside structs for the first field. 728 if startTemplate != nil { 729 start.Name = startTemplate.Name 730 start.Attr = append(start.Attr, startTemplate.Attr...) 731 } else if finfo != nil && finfo.name != "" { 732 start.Name.Local = finfo.name 733 start.Name.Space = finfo.xmlns 734 } else if typ.Name() != "" { 735 start.Name.Local = typ.Name() 736 } else { 737 // Must be a pointer to a named type, 738 // since it has the Marshaler methods. 739 start.Name.Local = typ.Elem().Name() 740 } 741 // Historic behaviour: elements use the name space of 742 // the element they are contained in by default. 743 if start.Name.Space == "" { 744 start.Name.Space = p.defaultNS 745 } 746 start.setDefaultNamespace() 747 return start 748 } 749 750 // marshalInterface marshals a Marshaler interface value. 751 func (p *printer) marshalInterface(val Marshaler, start StartElement) error { 752 // Push a marker onto the tag stack so that MarshalXML 753 // cannot close the XML tags that it did not open. 754 p.tags = append(p.tags, Name{}) 755 n := len(p.tags) 756 757 err := val.MarshalXML(p.encoder, start) 758 if err != nil { 759 return err 760 } 761 762 // Make sure MarshalXML closed all its tags. p.tags[n-1] is the mark. 763 if len(p.tags) > n { 764 return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local) 765 } 766 p.tags = p.tags[:n-1] 767 return nil 768 } 769 770 // marshalTextInterface marshals a TextMarshaler interface value. 771 func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error { 772 if err := p.writeStart(&start); err != nil { 773 return err 774 } 775 text, err := val.MarshalText() 776 if err != nil { 777 return err 778 } 779 EscapeText(p, text) 780 return p.writeEnd(start.Name) 781 } 782 783 // writeStart writes the given start element. 784 func (p *printer) writeStart(start *StartElement) error { 785 if start.Name.Local == "" { 786 return fmt.Errorf("xml: start tag with no name") 787 } 788 789 p.tags = append(p.tags, start.Name) 790 p.markPrefix() 791 // Define any name spaces explicitly declared in the attributes. 792 // We do this as a separate pass so that explicitly declared prefixes 793 // will take precedence over implicitly declared prefixes 794 // regardless of the order of the attributes. 795 ignoreNonEmptyDefault := start.Name.Space == "" 796 for _, attr := range start.Attr { 797 if err := p.defineNS(attr, ignoreNonEmptyDefault); err != nil { 798 return err 799 } 800 } 801 // Define any new name spaces implied by the attributes. 802 for _, attr := range start.Attr { 803 name := attr.Name 804 // From http://www.w3.org/TR/xml-names11/#defaulting 805 // "Default namespace declarations do not apply directly 806 // to attribute names; the interpretation of unprefixed 807 // attributes is determined by the element on which they 808 // appear." 809 // This means we don't need to create a new namespace 810 // when an attribute name space is empty. 811 if name.Space != "" && !name.isNamespace() { 812 p.createNSPrefix(name.Space, true) 813 } 814 } 815 p.createNSPrefix(start.Name.Space, false) 816 817 p.writeIndent(1) 818 p.WriteByte('<') 819 p.writeName(start.Name, false) 820 p.writeNamespaces() 821 for _, attr := range start.Attr { 822 name := attr.Name 823 if name.Local == "" || name.isNamespace() { 824 // Namespaces have already been written by writeNamespaces above. 825 continue 826 } 827 p.WriteByte(' ') 828 p.writeName(name, true) 829 p.WriteString(`="`) 830 p.EscapeString(attr.Value) 831 p.WriteByte('"') 832 } 833 p.WriteByte('>') 834 return nil 835 } 836 837 // writeName writes the given name. It assumes 838 // that p.createNSPrefix(name) has already been called. 839 func (p *printer) writeName(name Name, isAttr bool) { 840 if prefix := p.prefixForNS(name.Space, isAttr); prefix != "" { 841 p.WriteString(prefix) 842 p.WriteByte(':') 843 } 844 p.WriteString(name.Local) 845 } 846 847 func (p *printer) writeEnd(name Name) error { 848 if name.Local == "" { 849 return fmt.Errorf("xml: end tag with no name") 850 } 851 if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" { 852 return fmt.Errorf("xml: end tag </%s> without start tag", name.Local) 853 } 854 if top := p.tags[len(p.tags)-1]; top != name { 855 if top.Local != name.Local { 856 return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local) 857 } 858 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) 859 } 860 p.tags = p.tags[:len(p.tags)-1] 861 862 p.writeIndent(-1) 863 p.WriteByte('<') 864 p.WriteByte('/') 865 p.writeName(name, false) 866 p.WriteByte('>') 867 p.popPrefix() 868 return nil 869 } 870 871 func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) { 872 switch val.Kind() { 873 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 874 return strconv.FormatInt(val.Int(), 10), nil, nil 875 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 876 return strconv.FormatUint(val.Uint(), 10), nil, nil 877 case reflect.Float32, reflect.Float64: 878 return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil 879 case reflect.String: 880 return val.String(), nil, nil 881 case reflect.Bool: 882 return strconv.FormatBool(val.Bool()), nil, nil 883 case reflect.Array: 884 if typ.Elem().Kind() != reflect.Uint8 { 885 break 886 } 887 // [...]byte 888 var bytes []byte 889 if val.CanAddr() { 890 bytes = val.Slice(0, val.Len()).Bytes() 891 } else { 892 bytes = make([]byte, val.Len()) 893 reflect.Copy(reflect.ValueOf(bytes), val) 894 } 895 return "", bytes, nil 896 case reflect.Slice: 897 if typ.Elem().Kind() != reflect.Uint8 { 898 break 899 } 900 // []byte 901 return "", val.Bytes(), nil 902 } 903 return "", nil, &UnsupportedTypeError{typ} 904 } 905 906 var ddBytes = []byte("--") 907 908 func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { 909 s := parentStack{p: p} 910 for i := range tinfo.fields { 911 finfo := &tinfo.fields[i] 912 if finfo.flags&fAttr != 0 { 913 continue 914 } 915 vf := finfo.value(val) 916 917 // Dereference or skip nil pointer, interface values. 918 switch vf.Kind() { 919 case reflect.Ptr, reflect.Interface: 920 if !vf.IsNil() { 921 vf = vf.Elem() 922 } 923 } 924 925 switch finfo.flags & fMode { 926 case fCharData: 927 if vf.CanInterface() && vf.Type().Implements(textMarshalerType) { 928 data, err := vf.Interface().(encoding.TextMarshaler).MarshalText() 929 if err != nil { 930 return err 931 } 932 Escape(p, data) 933 continue 934 } 935 if vf.CanAddr() { 936 pv := vf.Addr() 937 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { 938 data, err := pv.Interface().(encoding.TextMarshaler).MarshalText() 939 if err != nil { 940 return err 941 } 942 Escape(p, data) 943 continue 944 } 945 } 946 var scratch [64]byte 947 switch vf.Kind() { 948 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 949 Escape(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)) 950 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 951 Escape(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)) 952 case reflect.Float32, reflect.Float64: 953 Escape(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())) 954 case reflect.Bool: 955 Escape(p, strconv.AppendBool(scratch[:0], vf.Bool())) 956 case reflect.String: 957 if err := EscapeText(p, []byte(vf.String())); err != nil { 958 return err 959 } 960 case reflect.Slice: 961 if elem, ok := vf.Interface().([]byte); ok { 962 if err := EscapeText(p, elem); err != nil { 963 return err 964 } 965 } 966 } 967 continue 968 969 case fComment: 970 k := vf.Kind() 971 if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) { 972 return fmt.Errorf("xml: bad type for comment field of %s", val.Type()) 973 } 974 if vf.Len() == 0 { 975 continue 976 } 977 p.writeIndent(0) 978 p.WriteString("<!--") 979 dashDash := false 980 dashLast := false 981 switch k { 982 case reflect.String: 983 s := vf.String() 984 dashDash = strings.Index(s, "--") >= 0 985 dashLast = s[len(s)-1] == '-' 986 if !dashDash { 987 p.WriteString(s) 988 } 989 case reflect.Slice: 990 b := vf.Bytes() 991 dashDash = bytes.Index(b, ddBytes) >= 0 992 dashLast = b[len(b)-1] == '-' 993 if !dashDash { 994 p.Write(b) 995 } 996 default: 997 panic("can't happen") 998 } 999 if dashDash { 1000 return fmt.Errorf(`xml: comments must not contain "--"`) 1001 } 1002 if dashLast { 1003 // "--->" is invalid grammar. Make it "- -->" 1004 p.WriteByte(' ') 1005 } 1006 p.WriteString("-->") 1007 continue 1008 1009 case fInnerXml: 1010 iface := vf.Interface() 1011 switch raw := iface.(type) { 1012 case []byte: 1013 p.Write(raw) 1014 continue 1015 case string: 1016 p.WriteString(raw) 1017 continue 1018 } 1019 1020 case fElement, fElement | fAny: 1021 if err := s.setParents(finfo, vf); err != nil { 1022 return err 1023 } 1024 } 1025 if err := p.marshalValue(vf, finfo, nil); err != nil { 1026 return err 1027 } 1028 } 1029 if err := s.setParents(&noField, reflect.Value{}); err != nil { 1030 return err 1031 } 1032 return p.cachedWriteError() 1033 } 1034 1035 var noField fieldInfo 1036 1037 // return the bufio Writer's cached write error 1038 func (p *printer) cachedWriteError() error { 1039 _, err := p.Write(nil) 1040 return err 1041 } 1042 1043 func (p *printer) writeIndent(depthDelta int) { 1044 if len(p.prefix) == 0 && len(p.indent) == 0 { 1045 return 1046 } 1047 if depthDelta < 0 { 1048 p.depth-- 1049 if p.indentedIn { 1050 p.indentedIn = false 1051 return 1052 } 1053 p.indentedIn = false 1054 } 1055 if p.putNewline { 1056 p.WriteByte('\n') 1057 } else { 1058 p.putNewline = true 1059 } 1060 if len(p.prefix) > 0 { 1061 p.WriteString(p.prefix) 1062 } 1063 if len(p.indent) > 0 { 1064 for i := 0; i < p.depth; i++ { 1065 p.WriteString(p.indent) 1066 } 1067 } 1068 if depthDelta > 0 { 1069 p.depth++ 1070 p.indentedIn = true 1071 } 1072 } 1073 1074 type parentStack struct { 1075 p *printer 1076 xmlns string 1077 parents []string 1078 } 1079 1080 // setParents sets the stack of current parents to those found in finfo. 1081 // It only writes the start elements if vf holds a non-nil value. 1082 // If finfo is &noField, it pops all elements. 1083 func (s *parentStack) setParents(finfo *fieldInfo, vf reflect.Value) error { 1084 xmlns := s.p.defaultNS 1085 if finfo.xmlns != "" { 1086 xmlns = finfo.xmlns 1087 } 1088 commonParents := 0 1089 if xmlns == s.xmlns { 1090 for ; commonParents < len(finfo.parents) && commonParents < len(s.parents); commonParents++ { 1091 if finfo.parents[commonParents] != s.parents[commonParents] { 1092 break 1093 } 1094 } 1095 } 1096 // Pop off any parents that aren't in common with the previous field. 1097 for i := len(s.parents) - 1; i >= commonParents; i-- { 1098 if err := s.p.writeEnd(Name{ 1099 Space: s.xmlns, 1100 Local: s.parents[i], 1101 }); err != nil { 1102 return err 1103 } 1104 } 1105 s.parents = finfo.parents 1106 s.xmlns = xmlns 1107 if commonParents >= len(s.parents) { 1108 // No new elements to push. 1109 return nil 1110 } 1111 if (vf.Kind() == reflect.Ptr || vf.Kind() == reflect.Interface) && vf.IsNil() { 1112 // The element is nil, so no need for the start elements. 1113 s.parents = s.parents[:commonParents] 1114 return nil 1115 } 1116 // Push any new parents required. 1117 for _, name := range s.parents[commonParents:] { 1118 start := &StartElement{ 1119 Name: Name{ 1120 Space: s.xmlns, 1121 Local: name, 1122 }, 1123 } 1124 // Set the default name space for parent elements 1125 // to match what we do with other elements. 1126 if s.xmlns != s.p.defaultNS { 1127 start.setDefaultNamespace() 1128 } 1129 if err := s.p.writeStart(start); err != nil { 1130 return err 1131 } 1132 } 1133 return nil 1134 } 1135 1136 // A MarshalXMLError is returned when Marshal encounters a type 1137 // that cannot be converted into XML. 1138 type UnsupportedTypeError struct { 1139 Type reflect.Type 1140 } 1141 1142 func (e *UnsupportedTypeError) Error() string { 1143 return "xml: unsupported type: " + e.Type.String() 1144 } 1145 1146 func isEmptyValue(v reflect.Value) bool { 1147 switch v.Kind() { 1148 case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 1149 return v.Len() == 0 1150 case reflect.Bool: 1151 return !v.Bool() 1152 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1153 return v.Int() == 0 1154 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 1155 return v.Uint() == 0 1156 case reflect.Float32, reflect.Float64: 1157 return v.Float() == 0 1158 case reflect.Interface, reflect.Ptr: 1159 return v.IsNil() 1160 } 1161 return false 1162 }