1
2
3
4
5 package xml
6
7 import (
8 "bytes"
9 "encoding"
10 "errors"
11 "fmt"
12 "reflect"
13 "runtime"
14 "strconv"
15 "strings"
16 )
17
18
19
20
21
22
23
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 func Unmarshal(data []byte, v any) error {
134 return NewDecoder(bytes.NewReader(data)).Decode(v)
135 }
136
137
138
139 func (d *Decoder) Decode(v any) error {
140 return d.DecodeElement(v, nil)
141 }
142
143
144
145
146
147 func (d *Decoder) DecodeElement(v any, start *StartElement) error {
148 val := reflect.ValueOf(v)
149 if val.Kind() != reflect.Pointer {
150 return errors.New("non-pointer passed to Unmarshal")
151 }
152
153 if val.IsNil() {
154 return errors.New("nil pointer passed to Unmarshal")
155 }
156 return d.unmarshal(val.Elem(), start)
157 }
158
159
160 type UnmarshalError string
161
162 func (e UnmarshalError) Error() string { return string(e) }
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179 type Unmarshaler interface {
180 UnmarshalXML(d *Decoder, start StartElement) error
181 }
182
183
184
185
186
187
188
189
190
191 type UnmarshalerAttr interface {
192 UnmarshalXMLAttr(attr Attr) error
193 }
194
195
196 func receiverType(val any) string {
197 t := reflect.TypeOf(val)
198 if t.Name() != "" {
199 return t.String()
200 }
201 return "(" + t.String() + ")"
202 }
203
204
205
206 func (d *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error {
207
208 d.pushEOF()
209
210 savedInUnmarshalXML := d.inUnmarshalXML
211 d.inUnmarshalXML = true
212 defer func() { d.inUnmarshalXML = savedInUnmarshalXML }()
213
214 err := val.UnmarshalXML(d, *start)
215 if err != nil {
216 d.popEOF()
217 return err
218 }
219
220 if !d.popEOF() {
221 return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(val), start.Name.Local)
222 }
223
224 return nil
225 }
226
227
228
229
230 func (d *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error {
231 var buf []byte
232 depth := 1
233 for depth > 0 {
234 t, err := d.Token()
235 if err != nil {
236 return err
237 }
238 switch t := t.(type) {
239 case CharData:
240 if depth == 1 {
241 buf = append(buf, t...)
242 }
243 case StartElement:
244 depth++
245 case EndElement:
246 depth--
247 }
248 }
249 return val.UnmarshalText(buf)
250 }
251
252
253 func (d *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
254 if val.Kind() == reflect.Pointer {
255 if val.IsNil() {
256 val.Set(reflect.New(val.Type().Elem()))
257 }
258 val = val.Elem()
259 }
260 if val.CanInterface() {
261
262
263 if unmarshaler, ok := reflect.TypeAssert[UnmarshalerAttr](val); ok {
264 return unmarshaler.UnmarshalXMLAttr(attr)
265 }
266 }
267 if val.CanAddr() {
268 pv := val.Addr()
269 if pv.CanInterface() {
270 if unmarshaler, ok := reflect.TypeAssert[UnmarshalerAttr](pv); ok {
271 return unmarshaler.UnmarshalXMLAttr(attr)
272 }
273 }
274 }
275
276
277 if val.CanInterface() {
278
279
280 if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](val); ok {
281 return textUnmarshaler.UnmarshalText([]byte(attr.Value))
282 }
283 }
284 if val.CanAddr() {
285 pv := val.Addr()
286 if pv.CanInterface() {
287 if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](pv); ok {
288 return textUnmarshaler.UnmarshalText([]byte(attr.Value))
289 }
290 }
291 }
292
293 if val.Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
294
295
296 n := val.Len()
297 val.Grow(1)
298 val.SetLen(n + 1)
299
300
301 if err := d.unmarshalAttr(val.Index(n), attr); err != nil {
302 val.SetLen(n)
303 return err
304 }
305 return nil
306 }
307
308 if val.Type() == attrType {
309 val.Set(reflect.ValueOf(attr))
310 return nil
311 }
312
313 return copyValue(val, []byte(attr.Value))
314 }
315
316 var attrType = reflect.TypeFor[Attr]()
317
318 const (
319 maxUnmarshalDepth = 10000
320 maxUnmarshalDepthWasm = 5000
321 )
322
323 var errUnmarshalDepth = errors.New("exceeded max depth")
324
325
326 func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
327 if d.stkDepth > maxUnmarshalDepth || runtime.GOARCH == "wasm" && d.stkDepth > maxUnmarshalDepthWasm {
328 return errUnmarshalDepth
329 }
330
331 if start == nil {
332 for {
333 tok, err := d.Token()
334 if err != nil {
335 return err
336 }
337 if t, ok := tok.(StartElement); ok {
338 start = &t
339 break
340 }
341 }
342 }
343
344
345
346 if val.Kind() == reflect.Interface && !val.IsNil() {
347 e := val.Elem()
348 if e.Kind() == reflect.Pointer && !e.IsNil() {
349 val = e
350 }
351 }
352
353 if val.Kind() == reflect.Pointer {
354 if val.IsNil() {
355 val.Set(reflect.New(val.Type().Elem()))
356 }
357 val = val.Elem()
358 }
359
360 if val.CanInterface() {
361
362
363 if unmarshaler, ok := reflect.TypeAssert[Unmarshaler](val); ok {
364 return d.unmarshalInterface(unmarshaler, start)
365 }
366 }
367
368 if val.CanAddr() {
369 pv := val.Addr()
370 if pv.CanInterface() {
371 if unmarshaler, ok := reflect.TypeAssert[Unmarshaler](pv); ok {
372 return d.unmarshalInterface(unmarshaler, start)
373 }
374 }
375 }
376
377 if val.CanInterface() {
378 if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](val); ok {
379 return d.unmarshalTextInterface(textUnmarshaler)
380 }
381 }
382
383 if val.CanAddr() {
384 pv := val.Addr()
385 if pv.CanInterface() {
386 if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](pv); ok {
387 return d.unmarshalTextInterface(textUnmarshaler)
388 }
389 }
390 }
391
392 var (
393 data []byte
394 saveData reflect.Value
395 comment []byte
396 saveComment reflect.Value
397 saveXML reflect.Value
398 saveXMLIndex int
399 saveXMLData []byte
400 saveAny reflect.Value
401 sv reflect.Value
402 tinfo *typeInfo
403 err error
404 )
405
406 switch v := val; v.Kind() {
407 default:
408 return errors.New("unknown type " + v.Type().String())
409
410 case reflect.Interface:
411
412
413
414 return d.Skip()
415
416 case reflect.Slice:
417 typ := v.Type()
418 if typ.Elem().Kind() == reflect.Uint8 {
419
420 saveData = v
421 break
422 }
423
424
425
426 n := v.Len()
427 v.Grow(1)
428 v.SetLen(n + 1)
429
430
431 if err := d.unmarshal(v.Index(n), start); err != nil {
432 v.SetLen(n)
433 return err
434 }
435 return nil
436
437 case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
438 saveData = v
439
440 case reflect.Struct:
441 typ := v.Type()
442 if typ == nameType {
443 v.Set(reflect.ValueOf(start.Name))
444 break
445 }
446
447 sv = v
448 tinfo, err = getTypeInfo(typ)
449 if err != nil {
450 return err
451 }
452
453
454 if tinfo.xmlname != nil {
455 finfo := tinfo.xmlname
456 if finfo.name != "" && finfo.name != start.Name.Local {
457 return UnmarshalError("expected element type <" + finfo.name + "> but have <" + start.Name.Local + ">")
458 }
459 if finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
460 e := "expected element <" + finfo.name + "> in name space " + finfo.xmlns + " but have "
461 if start.Name.Space == "" {
462 e += "no name space"
463 } else {
464 e += start.Name.Space
465 }
466 return UnmarshalError(e)
467 }
468 fv := finfo.value(sv, initNilPointers)
469 if _, ok := reflect.TypeAssert[Name](fv); ok {
470 fv.Set(reflect.ValueOf(start.Name))
471 }
472 }
473
474
475 for _, a := range start.Attr {
476 handled := false
477 any := -1
478 for i := range tinfo.fields {
479 finfo := &tinfo.fields[i]
480 switch finfo.flags & fMode {
481 case fAttr:
482 strv := finfo.value(sv, initNilPointers)
483 if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
484 if err := d.unmarshalAttr(strv, a); err != nil {
485 return err
486 }
487 handled = true
488 }
489
490 case fAny | fAttr:
491 if any == -1 {
492 any = i
493 }
494 }
495 }
496 if !handled && any >= 0 {
497 finfo := &tinfo.fields[any]
498 strv := finfo.value(sv, initNilPointers)
499 if err := d.unmarshalAttr(strv, a); err != nil {
500 return err
501 }
502 }
503 }
504
505
506 for i := range tinfo.fields {
507 finfo := &tinfo.fields[i]
508 switch finfo.flags & fMode {
509 case fCDATA, fCharData:
510 if !saveData.IsValid() {
511 saveData = finfo.value(sv, initNilPointers)
512 }
513
514 case fComment:
515 if !saveComment.IsValid() {
516 saveComment = finfo.value(sv, initNilPointers)
517 }
518
519 case fAny, fAny | fElement:
520 if !saveAny.IsValid() {
521 saveAny = finfo.value(sv, initNilPointers)
522 }
523
524 case fInnerXML:
525 if !saveXML.IsValid() {
526 saveXML = finfo.value(sv, initNilPointers)
527 if d.saved == nil {
528 saveXMLIndex = 0
529 d.saved = new(bytes.Buffer)
530 } else {
531 saveXMLIndex = d.savedOffset()
532 }
533 }
534 }
535 }
536 }
537
538
539
540 Loop:
541 for {
542 var savedOffset int
543 if saveXML.IsValid() {
544 savedOffset = d.savedOffset()
545 }
546 tok, err := d.Token()
547 if err != nil {
548 return err
549 }
550 switch t := tok.(type) {
551 case StartElement:
552 consumed := false
553 if sv.IsValid() {
554 consumed, err = d.unmarshalPath(tinfo, sv, nil, &t)
555 if err != nil {
556 return err
557 }
558 if !consumed && saveAny.IsValid() {
559 consumed = true
560 if err := d.unmarshal(saveAny, &t); err != nil {
561 return err
562 }
563 }
564 }
565 if !consumed {
566 if err := d.Skip(); err != nil {
567 return err
568 }
569 }
570
571 case EndElement:
572 if saveXML.IsValid() {
573 saveXMLData = d.saved.Bytes()[saveXMLIndex:savedOffset]
574 if saveXMLIndex == 0 {
575 d.saved = nil
576 }
577 }
578 break Loop
579
580 case CharData:
581 if saveData.IsValid() {
582 data = append(data, t...)
583 }
584
585 case Comment:
586 if saveComment.IsValid() {
587 comment = append(comment, t...)
588 }
589 }
590 }
591
592 if saveData.IsValid() && saveData.CanInterface() {
593 if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](saveData); ok {
594 if err := textUnmarshaler.UnmarshalText(data); err != nil {
595 return err
596 }
597 saveData = reflect.Value{}
598 }
599 }
600
601 if saveData.IsValid() && saveData.CanAddr() {
602 pv := saveData.Addr()
603 if pv.CanInterface() {
604 if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](pv); ok {
605 if err := textUnmarshaler.UnmarshalText(data); err != nil {
606 return err
607 }
608 saveData = reflect.Value{}
609 }
610 }
611 }
612
613 if err := copyValue(saveData, data); err != nil {
614 return err
615 }
616
617 switch t := saveComment; t.Kind() {
618 case reflect.String:
619 t.SetString(string(comment))
620 case reflect.Slice:
621 t.Set(reflect.ValueOf(comment))
622 }
623
624 switch t := saveXML; t.Kind() {
625 case reflect.String:
626 t.SetString(string(saveXMLData))
627 case reflect.Slice:
628 if t.Type().Elem().Kind() == reflect.Uint8 {
629 t.Set(reflect.ValueOf(saveXMLData))
630 }
631 }
632
633 return nil
634 }
635
636 func copyValue(dst reflect.Value, src []byte) (err error) {
637 dst0 := dst
638
639 if dst.Kind() == reflect.Pointer {
640 if dst.IsNil() {
641 dst.Set(reflect.New(dst.Type().Elem()))
642 }
643 dst = dst.Elem()
644 }
645
646
647 switch dst.Kind() {
648 case reflect.Invalid:
649
650 default:
651 return errors.New("cannot unmarshal into " + dst0.Type().String())
652 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
653 if len(src) == 0 {
654 dst.SetInt(0)
655 return nil
656 }
657 itmp, err := strconv.ParseInt(strings.TrimSpace(string(src)), 10, dst.Type().Bits())
658 if err != nil {
659 return err
660 }
661 dst.SetInt(itmp)
662 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
663 if len(src) == 0 {
664 dst.SetUint(0)
665 return nil
666 }
667 utmp, err := strconv.ParseUint(strings.TrimSpace(string(src)), 10, dst.Type().Bits())
668 if err != nil {
669 return err
670 }
671 dst.SetUint(utmp)
672 case reflect.Float32, reflect.Float64:
673 if len(src) == 0 {
674 dst.SetFloat(0)
675 return nil
676 }
677 ftmp, err := strconv.ParseFloat(strings.TrimSpace(string(src)), dst.Type().Bits())
678 if err != nil {
679 return err
680 }
681 dst.SetFloat(ftmp)
682 case reflect.Bool:
683 if len(src) == 0 {
684 dst.SetBool(false)
685 return nil
686 }
687 value, err := strconv.ParseBool(strings.TrimSpace(string(src)))
688 if err != nil {
689 return err
690 }
691 dst.SetBool(value)
692 case reflect.String:
693 dst.SetString(string(src))
694 case reflect.Slice:
695 if len(src) == 0 {
696
697 src = []byte{}
698 }
699 dst.SetBytes(src)
700 }
701 return nil
702 }
703
704
705
706
707
708
709 func (d *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) {
710 recurse := false
711 Loop:
712 for i := range tinfo.fields {
713 finfo := &tinfo.fields[i]
714 if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
715 continue
716 }
717 for j := range parents {
718 if parents[j] != finfo.parents[j] {
719 continue Loop
720 }
721 }
722 if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local {
723
724 return true, d.unmarshal(finfo.value(sv, initNilPointers), start)
725 }
726 if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local {
727
728
729
730 recurse = true
731
732
733
734 parents = finfo.parents[:len(parents)+1]
735 break
736 }
737 }
738 if !recurse {
739
740 return false, nil
741 }
742
743
744
745 for {
746 var tok Token
747 tok, err = d.Token()
748 if err != nil {
749 return true, err
750 }
751 switch t := tok.(type) {
752 case StartElement:
753 consumed2, err := d.unmarshalPath(tinfo, sv, parents, &t)
754 if err != nil {
755 return true, err
756 }
757 if !consumed2 {
758 if err := d.Skip(); err != nil {
759 return true, err
760 }
761 }
762 case EndElement:
763 return true, nil
764 }
765 }
766 }
767
768
769
770
771
772
773 func (d *Decoder) Skip() error {
774 var depth int64
775 for {
776 tok, err := d.Token()
777 if err != nil {
778 return err
779 }
780 switch tok.(type) {
781 case StartElement:
782 depth++
783 case EndElement:
784 if depth == 0 {
785 return nil
786 }
787 depth--
788 }
789 }
790 }
791
View as plain text