1
2
3
4
5 package xml
6
7 import (
8 "bufio"
9 "bytes"
10 "encoding"
11 "errors"
12 "fmt"
13 "io"
14 "reflect"
15 "strconv"
16 "strings"
17 )
18
19 const (
20
21
22
23 Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
24 )
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 func Marshal(v any) ([]byte, error) {
83 var b bytes.Buffer
84 enc := NewEncoder(&b)
85 if err := enc.Encode(v); err != nil {
86 return nil, err
87 }
88 if err := enc.Close(); err != nil {
89 return nil, err
90 }
91 return b.Bytes(), nil
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 type Marshaler interface {
111 MarshalXML(e *Encoder, start StartElement) error
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125 type MarshalerAttr interface {
126 MarshalXMLAttr(name Name) (Attr, error)
127 }
128
129
130
131
132 func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
133 var b bytes.Buffer
134 enc := NewEncoder(&b)
135 enc.Indent(prefix, indent)
136 if err := enc.Encode(v); err != nil {
137 return nil, err
138 }
139 if err := enc.Close(); err != nil {
140 return nil, err
141 }
142 return b.Bytes(), nil
143 }
144
145
146 type Encoder struct {
147 p printer
148 }
149
150
151 func NewEncoder(w io.Writer) *Encoder {
152 e := &Encoder{printer{w: bufio.NewWriter(w)}}
153 e.p.encoder = e
154 return e
155 }
156
157
158
159
160 func (enc *Encoder) Indent(prefix, indent string) {
161 enc.p.prefix = prefix
162 enc.p.indent = indent
163 }
164
165
166
167
168
169
170
171 func (enc *Encoder) Encode(v any) error {
172 err := enc.p.marshalValue(reflect.ValueOf(v), nil, nil)
173 if err != nil {
174 return err
175 }
176 return enc.p.w.Flush()
177 }
178
179
180
181
182
183
184
185
186 func (enc *Encoder) EncodeElement(v any, start StartElement) error {
187 err := enc.p.marshalValue(reflect.ValueOf(v), nil, &start)
188 if err != nil {
189 return err
190 }
191 return enc.p.w.Flush()
192 }
193
194 var (
195 begComment = []byte("<!--")
196 endComment = []byte("-->")
197 endProcInst = []byte("?>")
198 )
199
200
201
202
203
204
205
206
207
208
209
210
211
212 func (enc *Encoder) EncodeToken(t Token) error {
213
214 p := &enc.p
215 switch t := t.(type) {
216 case StartElement:
217 if err := p.writeStart(&t); err != nil {
218 return err
219 }
220 case EndElement:
221 if err := p.writeEnd(t.Name); err != nil {
222 return err
223 }
224 case CharData:
225 escapeText(p, t, false)
226 case Comment:
227 if bytes.Contains(t, endComment) {
228 return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
229 }
230 p.WriteString("<!--")
231 p.Write(t)
232 p.WriteString("-->")
233 return p.cachedWriteError()
234 case ProcInst:
235
236
237 if t.Target == "xml" && p.w.Buffered() != 0 {
238 return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
239 }
240 if !isNameString(t.Target) {
241 return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
242 }
243 if bytes.Contains(t.Inst, endProcInst) {
244 return fmt.Errorf("xml: EncodeToken of ProcInst containing ?> marker")
245 }
246 p.WriteString("<?")
247 p.WriteString(t.Target)
248 if len(t.Inst) > 0 {
249 p.WriteByte(' ')
250 p.Write(t.Inst)
251 }
252 p.WriteString("?>")
253 case Directive:
254 if !isValidDirective(t) {
255 return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers")
256 }
257 p.WriteString("<!")
258 p.Write(t)
259 p.WriteString(">")
260 default:
261 return fmt.Errorf("xml: EncodeToken of invalid token type")
262
263 }
264 return p.cachedWriteError()
265 }
266
267
268
269 func isValidDirective(dir Directive) bool {
270 var (
271 depth int
272 inquote uint8
273 incomment bool
274 )
275 for i, c := range dir {
276 switch {
277 case incomment:
278 if c == '>' {
279 if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) {
280 incomment = false
281 }
282 }
283
284 case inquote != 0:
285 if c == inquote {
286 inquote = 0
287 }
288
289 case c == '\'' || c == '"':
290 inquote = c
291 case c == '<':
292 if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) {
293 incomment = true
294 } else {
295 depth++
296 }
297 case c == '>':
298 if depth == 0 {
299 return false
300 }
301 depth--
302 }
303 }
304 return depth == 0 && inquote == 0 && !incomment
305 }
306
307
308
309 func (enc *Encoder) Flush() error {
310 return enc.p.w.Flush()
311 }
312
313
314
315
316 func (enc *Encoder) Close() error {
317 return enc.p.Close()
318 }
319
320 type printer struct {
321 w *bufio.Writer
322 encoder *Encoder
323 seq int
324 indent string
325 prefix string
326 depth int
327 indentedIn bool
328 putNewline bool
329 attrNS map[string]string
330 attrPrefix map[string]string
331 prefixes []string
332 tags []Name
333 closed bool
334 err error
335 }
336
337
338
339 func (p *printer) createAttrPrefix(url string) string {
340 if prefix := p.attrPrefix[url]; prefix != "" {
341 return prefix
342 }
343
344
345
346
347
348 if url == xmlURL {
349 return xmlPrefix
350 }
351
352
353 if p.attrPrefix == nil {
354 p.attrPrefix = make(map[string]string)
355 p.attrNS = make(map[string]string)
356 }
357
358
359
360 prefix := strings.TrimRight(url, "/")
361 if i := strings.LastIndex(prefix, "/"); i >= 0 {
362 prefix = prefix[i+1:]
363 }
364 if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
365 prefix = "_"
366 }
367
368
369
370
371 if len(prefix) >= 3 && strings.EqualFold(prefix[:3], "xml") {
372 prefix = "_" + prefix
373 }
374 if p.attrNS[prefix] != "" {
375
376 for p.seq++; ; p.seq++ {
377 if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" {
378 prefix = id
379 break
380 }
381 }
382 }
383
384 p.attrPrefix[url] = prefix
385 p.attrNS[prefix] = url
386
387 p.WriteString(`xmlns:`)
388 p.WriteString(prefix)
389 p.WriteString(`="`)
390 EscapeText(p, []byte(url))
391 p.WriteString(`" `)
392
393 p.prefixes = append(p.prefixes, prefix)
394
395 return prefix
396 }
397
398
399 func (p *printer) deleteAttrPrefix(prefix string) {
400 delete(p.attrPrefix, p.attrNS[prefix])
401 delete(p.attrNS, prefix)
402 }
403
404 func (p *printer) markPrefix() {
405 p.prefixes = append(p.prefixes, "")
406 }
407
408 func (p *printer) popPrefix() {
409 for len(p.prefixes) > 0 {
410 prefix := p.prefixes[len(p.prefixes)-1]
411 p.prefixes = p.prefixes[:len(p.prefixes)-1]
412 if prefix == "" {
413 break
414 }
415 p.deleteAttrPrefix(prefix)
416 }
417 }
418
419 var (
420 marshalerType = reflect.TypeFor[Marshaler]()
421 marshalerAttrType = reflect.TypeFor[MarshalerAttr]()
422 textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]()
423 )
424
425
426
427 func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error {
428 if startTemplate != nil && startTemplate.Name.Local == "" {
429 return fmt.Errorf("xml: EncodeElement of StartElement with missing name")
430 }
431
432 if !val.IsValid() {
433 return nil
434 }
435 if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) {
436 return nil
437 }
438
439
440
441
442 for val.Kind() == reflect.Interface || val.Kind() == reflect.Pointer {
443 if val.IsNil() {
444 return nil
445 }
446 val = val.Elem()
447 }
448
449 kind := val.Kind()
450 typ := val.Type()
451
452
453 if val.CanInterface() && typ.Implements(marshalerType) {
454 return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate))
455 }
456 if val.CanAddr() {
457 pv := val.Addr()
458 if pv.CanInterface() && pv.Type().Implements(marshalerType) {
459 return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate))
460 }
461 }
462
463
464 if val.CanInterface() && typ.Implements(textMarshalerType) {
465 return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), defaultStart(typ, finfo, startTemplate))
466 }
467 if val.CanAddr() {
468 pv := val.Addr()
469 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
470 return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), defaultStart(pv.Type(), finfo, startTemplate))
471 }
472 }
473
474
475 if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
476 for i, n := 0, val.Len(); i < n; i++ {
477 if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil {
478 return err
479 }
480 }
481 return nil
482 }
483
484 tinfo, err := getTypeInfo(typ)
485 if err != nil {
486 return err
487 }
488
489
490
491
492
493
494
495 var start StartElement
496
497 if startTemplate != nil {
498 start.Name = startTemplate.Name
499 start.Attr = append(start.Attr, startTemplate.Attr...)
500 } else if tinfo.xmlname != nil {
501 xmlname := tinfo.xmlname
502 if xmlname.name != "" {
503 start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
504 } else {
505 fv := xmlname.value(val, dontInitNilPointers)
506 if v, ok := fv.Interface().(Name); ok && v.Local != "" {
507 start.Name = v
508 }
509 }
510 }
511 if start.Name.Local == "" && finfo != nil {
512 start.Name.Space, start.Name.Local = finfo.xmlns, finfo.name
513 }
514 if start.Name.Local == "" {
515 name := typ.Name()
516 if i := strings.IndexByte(name, '['); i >= 0 {
517
518 name = name[:i]
519 }
520 if name == "" {
521 return &UnsupportedTypeError{typ}
522 }
523 start.Name.Local = name
524 }
525
526
527 for i := range tinfo.fields {
528 finfo := &tinfo.fields[i]
529 if finfo.flags&fAttr == 0 {
530 continue
531 }
532 fv := finfo.value(val, dontInitNilPointers)
533
534 if finfo.flags&fOmitEmpty != 0 && (!fv.IsValid() || isEmptyValue(fv)) {
535 continue
536 }
537
538 if fv.Kind() == reflect.Interface && fv.IsNil() {
539 continue
540 }
541
542 name := Name{Space: finfo.xmlns, Local: finfo.name}
543 if err := p.marshalAttr(&start, name, fv); err != nil {
544 return err
545 }
546 }
547
548
549 if tinfo.xmlname != nil && start.Name.Space == "" &&
550 tinfo.xmlname.xmlns == "" && tinfo.xmlname.name == "" &&
551 len(p.tags) != 0 && p.tags[len(p.tags)-1].Space != "" {
552 start.Attr = append(start.Attr, Attr{Name{"", xmlnsPrefix}, ""})
553 }
554 if err := p.writeStart(&start); err != nil {
555 return err
556 }
557
558 if val.Kind() == reflect.Struct {
559 err = p.marshalStruct(tinfo, val)
560 } else {
561 s, b, err1 := p.marshalSimple(typ, val)
562 if err1 != nil {
563 err = err1
564 } else if b != nil {
565 EscapeText(p, b)
566 } else {
567 p.EscapeString(s)
568 }
569 }
570 if err != nil {
571 return err
572 }
573
574 if err := p.writeEnd(start.Name); err != nil {
575 return err
576 }
577
578 return p.cachedWriteError()
579 }
580
581
582 func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) error {
583 if val.CanInterface() && val.Type().Implements(marshalerAttrType) {
584 attr, err := val.Interface().(MarshalerAttr).MarshalXMLAttr(name)
585 if err != nil {
586 return err
587 }
588 if attr.Name.Local != "" {
589 start.Attr = append(start.Attr, attr)
590 }
591 return nil
592 }
593
594 if val.CanAddr() {
595 pv := val.Addr()
596 if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
597 attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
598 if err != nil {
599 return err
600 }
601 if attr.Name.Local != "" {
602 start.Attr = append(start.Attr, attr)
603 }
604 return nil
605 }
606 }
607
608 if val.CanInterface() && val.Type().Implements(textMarshalerType) {
609 text, err := val.Interface().(encoding.TextMarshaler).MarshalText()
610 if err != nil {
611 return err
612 }
613 start.Attr = append(start.Attr, Attr{name, string(text)})
614 return nil
615 }
616
617 if val.CanAddr() {
618 pv := val.Addr()
619 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
620 text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
621 if err != nil {
622 return err
623 }
624 start.Attr = append(start.Attr, Attr{name, string(text)})
625 return nil
626 }
627 }
628
629
630 switch val.Kind() {
631 case reflect.Pointer, reflect.Interface:
632 if val.IsNil() {
633 return nil
634 }
635 val = val.Elem()
636 }
637
638
639 if val.Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
640 n := val.Len()
641 for i := 0; i < n; i++ {
642 if err := p.marshalAttr(start, name, val.Index(i)); err != nil {
643 return err
644 }
645 }
646 return nil
647 }
648
649 if val.Type() == attrType {
650 start.Attr = append(start.Attr, val.Interface().(Attr))
651 return nil
652 }
653
654 s, b, err := p.marshalSimple(val.Type(), val)
655 if err != nil {
656 return err
657 }
658 if b != nil {
659 s = string(b)
660 }
661 start.Attr = append(start.Attr, Attr{name, s})
662 return nil
663 }
664
665
666
667 func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
668 var start StartElement
669
670
671 if startTemplate != nil {
672 start.Name = startTemplate.Name
673 start.Attr = append(start.Attr, startTemplate.Attr...)
674 } else if finfo != nil && finfo.name != "" {
675 start.Name.Local = finfo.name
676 start.Name.Space = finfo.xmlns
677 } else if typ.Name() != "" {
678 start.Name.Local = typ.Name()
679 } else {
680
681
682 start.Name.Local = typ.Elem().Name()
683 }
684 return start
685 }
686
687
688 func (p *printer) marshalInterface(val Marshaler, start StartElement) error {
689
690
691 p.tags = append(p.tags, Name{})
692 n := len(p.tags)
693
694 err := val.MarshalXML(p.encoder, start)
695 if err != nil {
696 return err
697 }
698
699
700 if len(p.tags) > n {
701 return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local)
702 }
703 p.tags = p.tags[:n-1]
704 return nil
705 }
706
707
708 func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error {
709 if err := p.writeStart(&start); err != nil {
710 return err
711 }
712 text, err := val.MarshalText()
713 if err != nil {
714 return err
715 }
716 EscapeText(p, text)
717 return p.writeEnd(start.Name)
718 }
719
720
721 func (p *printer) writeStart(start *StartElement) error {
722 if start.Name.Local == "" {
723 return fmt.Errorf("xml: start tag with no name")
724 }
725
726 p.tags = append(p.tags, start.Name)
727 p.markPrefix()
728
729 p.writeIndent(1)
730 p.WriteByte('<')
731 p.WriteString(start.Name.Local)
732
733 if start.Name.Space != "" {
734 p.WriteString(` xmlns="`)
735 p.EscapeString(start.Name.Space)
736 p.WriteByte('"')
737 }
738
739
740 for _, attr := range start.Attr {
741 name := attr.Name
742 if name.Local == "" {
743 continue
744 }
745 p.WriteByte(' ')
746 if name.Space != "" {
747 p.WriteString(p.createAttrPrefix(name.Space))
748 p.WriteByte(':')
749 }
750 p.WriteString(name.Local)
751 p.WriteString(`="`)
752 p.EscapeString(attr.Value)
753 p.WriteByte('"')
754 }
755 p.WriteByte('>')
756 return nil
757 }
758
759 func (p *printer) writeEnd(name Name) error {
760 if name.Local == "" {
761 return fmt.Errorf("xml: end tag with no name")
762 }
763 if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" {
764 return fmt.Errorf("xml: end tag </%s> without start tag", name.Local)
765 }
766 if top := p.tags[len(p.tags)-1]; top != name {
767 if top.Local != name.Local {
768 return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local)
769 }
770 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)
771 }
772 p.tags = p.tags[:len(p.tags)-1]
773
774 p.writeIndent(-1)
775 p.WriteByte('<')
776 p.WriteByte('/')
777 p.WriteString(name.Local)
778 p.WriteByte('>')
779 p.popPrefix()
780 return nil
781 }
782
783 func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) {
784 switch val.Kind() {
785 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
786 return strconv.FormatInt(val.Int(), 10), nil, nil
787 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
788 return strconv.FormatUint(val.Uint(), 10), nil, nil
789 case reflect.Float32, reflect.Float64:
790 return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil
791 case reflect.String:
792 return val.String(), nil, nil
793 case reflect.Bool:
794 return strconv.FormatBool(val.Bool()), nil, nil
795 case reflect.Array:
796 if typ.Elem().Kind() != reflect.Uint8 {
797 break
798 }
799
800 var bytes []byte
801 if val.CanAddr() {
802 bytes = val.Bytes()
803 } else {
804 bytes = make([]byte, val.Len())
805 reflect.Copy(reflect.ValueOf(bytes), val)
806 }
807 return "", bytes, nil
808 case reflect.Slice:
809 if typ.Elem().Kind() != reflect.Uint8 {
810 break
811 }
812
813 return "", val.Bytes(), nil
814 }
815 return "", nil, &UnsupportedTypeError{typ}
816 }
817
818 var ddBytes = []byte("--")
819
820
821
822
823
824 func indirect(vf reflect.Value) reflect.Value {
825 for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Pointer {
826 if vf.IsNil() {
827 return vf
828 }
829 vf = vf.Elem()
830 }
831 return vf
832 }
833
834 func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
835 s := parentStack{p: p}
836 for i := range tinfo.fields {
837 finfo := &tinfo.fields[i]
838 if finfo.flags&fAttr != 0 {
839 continue
840 }
841 vf := finfo.value(val, dontInitNilPointers)
842 if !vf.IsValid() {
843
844
845 continue
846 }
847
848 switch finfo.flags & fMode {
849 case fCDATA, fCharData:
850 emit := EscapeText
851 if finfo.flags&fMode == fCDATA {
852 emit = emitCDATA
853 }
854 if err := s.trim(finfo.parents); err != nil {
855 return err
856 }
857 if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
858 data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
859 if err != nil {
860 return err
861 }
862 if err := emit(p, data); err != nil {
863 return err
864 }
865 continue
866 }
867 if vf.CanAddr() {
868 pv := vf.Addr()
869 if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
870 data, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
871 if err != nil {
872 return err
873 }
874 if err := emit(p, data); err != nil {
875 return err
876 }
877 continue
878 }
879 }
880
881 var scratch [64]byte
882 vf = indirect(vf)
883 switch vf.Kind() {
884 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
885 if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil {
886 return err
887 }
888 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
889 if err := emit(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)); err != nil {
890 return err
891 }
892 case reflect.Float32, reflect.Float64:
893 if err := emit(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())); err != nil {
894 return err
895 }
896 case reflect.Bool:
897 if err := emit(p, strconv.AppendBool(scratch[:0], vf.Bool())); err != nil {
898 return err
899 }
900 case reflect.String:
901 if err := emit(p, []byte(vf.String())); err != nil {
902 return err
903 }
904 case reflect.Slice:
905 if elem, ok := vf.Interface().([]byte); ok {
906 if err := emit(p, elem); err != nil {
907 return err
908 }
909 }
910 }
911 continue
912
913 case fComment:
914 if err := s.trim(finfo.parents); err != nil {
915 return err
916 }
917 vf = indirect(vf)
918 k := vf.Kind()
919 if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
920 return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
921 }
922 if vf.Len() == 0 {
923 continue
924 }
925 p.writeIndent(0)
926 p.WriteString("<!--")
927 dashDash := false
928 dashLast := false
929 switch k {
930 case reflect.String:
931 s := vf.String()
932 dashDash = strings.Contains(s, "--")
933 dashLast = s[len(s)-1] == '-'
934 if !dashDash {
935 p.WriteString(s)
936 }
937 case reflect.Slice:
938 b := vf.Bytes()
939 dashDash = bytes.Contains(b, ddBytes)
940 dashLast = b[len(b)-1] == '-'
941 if !dashDash {
942 p.Write(b)
943 }
944 default:
945 panic("can't happen")
946 }
947 if dashDash {
948 return fmt.Errorf(`xml: comments must not contain "--"`)
949 }
950 if dashLast {
951
952 p.WriteByte(' ')
953 }
954 p.WriteString("-->")
955 continue
956
957 case fInnerXML:
958 vf = indirect(vf)
959 iface := vf.Interface()
960 switch raw := iface.(type) {
961 case []byte:
962 p.Write(raw)
963 continue
964 case string:
965 p.WriteString(raw)
966 continue
967 }
968
969 case fElement, fElement | fAny:
970 if err := s.trim(finfo.parents); err != nil {
971 return err
972 }
973 if len(finfo.parents) > len(s.stack) {
974 if vf.Kind() != reflect.Pointer && vf.Kind() != reflect.Interface || !vf.IsNil() {
975 if err := s.push(finfo.parents[len(s.stack):]); err != nil {
976 return err
977 }
978 }
979 }
980 }
981 if err := p.marshalValue(vf, finfo, nil); err != nil {
982 return err
983 }
984 }
985 s.trim(nil)
986 return p.cachedWriteError()
987 }
988
989
990 func (p *printer) Write(b []byte) (n int, err error) {
991 if p.closed && p.err == nil {
992 p.err = errors.New("use of closed Encoder")
993 }
994 if p.err == nil {
995 n, p.err = p.w.Write(b)
996 }
997 return n, p.err
998 }
999
1000
1001 func (p *printer) WriteString(s string) (n int, err error) {
1002 if p.closed && p.err == nil {
1003 p.err = errors.New("use of closed Encoder")
1004 }
1005 if p.err == nil {
1006 n, p.err = p.w.WriteString(s)
1007 }
1008 return n, p.err
1009 }
1010
1011
1012 func (p *printer) WriteByte(c byte) error {
1013 if p.closed && p.err == nil {
1014 p.err = errors.New("use of closed Encoder")
1015 }
1016 if p.err == nil {
1017 p.err = p.w.WriteByte(c)
1018 }
1019 return p.err
1020 }
1021
1022
1023
1024
1025 func (p *printer) Close() error {
1026 if p.closed {
1027 return nil
1028 }
1029 p.closed = true
1030 if err := p.w.Flush(); err != nil {
1031 return err
1032 }
1033 if len(p.tags) > 0 {
1034 return fmt.Errorf("unclosed tag <%s>", p.tags[len(p.tags)-1].Local)
1035 }
1036 return nil
1037 }
1038
1039
1040 func (p *printer) cachedWriteError() error {
1041 _, err := p.Write(nil)
1042 return err
1043 }
1044
1045 func (p *printer) writeIndent(depthDelta int) {
1046 if len(p.prefix) == 0 && len(p.indent) == 0 {
1047 return
1048 }
1049 if depthDelta < 0 {
1050 p.depth--
1051 if p.indentedIn {
1052 p.indentedIn = false
1053 return
1054 }
1055 p.indentedIn = false
1056 }
1057 if p.putNewline {
1058 p.WriteByte('\n')
1059 } else {
1060 p.putNewline = true
1061 }
1062 if len(p.prefix) > 0 {
1063 p.WriteString(p.prefix)
1064 }
1065 if len(p.indent) > 0 {
1066 for i := 0; i < p.depth; i++ {
1067 p.WriteString(p.indent)
1068 }
1069 }
1070 if depthDelta > 0 {
1071 p.depth++
1072 p.indentedIn = true
1073 }
1074 }
1075
1076 type parentStack struct {
1077 p *printer
1078 stack []string
1079 }
1080
1081
1082
1083
1084 func (s *parentStack) trim(parents []string) error {
1085 split := 0
1086 for ; split < len(parents) && split < len(s.stack); split++ {
1087 if parents[split] != s.stack[split] {
1088 break
1089 }
1090 }
1091 for i := len(s.stack) - 1; i >= split; i-- {
1092 if err := s.p.writeEnd(Name{Local: s.stack[i]}); err != nil {
1093 return err
1094 }
1095 }
1096 s.stack = s.stack[:split]
1097 return nil
1098 }
1099
1100
1101 func (s *parentStack) push(parents []string) error {
1102 for i := 0; i < len(parents); i++ {
1103 if err := s.p.writeStart(&StartElement{Name: Name{Local: parents[i]}}); err != nil {
1104 return err
1105 }
1106 }
1107 s.stack = append(s.stack, parents...)
1108 return nil
1109 }
1110
1111
1112
1113 type UnsupportedTypeError struct {
1114 Type reflect.Type
1115 }
1116
1117 func (e *UnsupportedTypeError) Error() string {
1118 return "xml: unsupported type: " + e.Type.String()
1119 }
1120
1121 func isEmptyValue(v reflect.Value) bool {
1122 switch v.Kind() {
1123 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
1124 return v.Len() == 0
1125 case reflect.Bool,
1126 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
1127 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
1128 reflect.Float32, reflect.Float64,
1129 reflect.Interface, reflect.Pointer:
1130 return v.IsZero()
1131 }
1132 return false
1133 }
1134
View as plain text