1// Copyright 2009 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
5package xml
6
7import (
8	"bytes"
9	"encoding"
10	"errors"
11	"fmt"
12	"reflect"
13	"runtime"
14	"strconv"
15	"strings"
16)
17
18// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
19// an XML element is an order-dependent collection of anonymous
20// values, while a data structure is an order-independent collection
21// of named values.
22// See [encoding/json] for a textual representation more suitable
23// to data structures.
24
25// Unmarshal parses the XML-encoded data and stores the result in
26// the value pointed to by v, which must be an arbitrary struct,
27// slice, or string. Well-formed data that does not fit into v is
28// discarded.
29//
30// Because Unmarshal uses the reflect package, it can only assign
31// to exported (upper case) fields. Unmarshal uses a case-sensitive
32// comparison to match XML element names to tag values and struct
33// field names.
34//
35// Unmarshal maps an XML element to a struct using the following rules.
36// In the rules, the tag of a field refers to the value associated with the
37// key 'xml' in the struct field's tag (see the example above).
38//
39//   - If the struct has a field of type []byte or string with tag
40//     ",innerxml", Unmarshal accumulates the raw XML nested inside the
41//     element in that field. The rest of the rules still apply.
42//
43//   - If the struct has a field named XMLName of type Name,
44//     Unmarshal records the element name in that field.
45//
46//   - If the XMLName field has an associated tag of the form
47//     "name" or "namespace-URL name", the XML element must have
48//     the given name (and, optionally, name space) or else Unmarshal
49//     returns an error.
50//
51//   - If the XML element has an attribute whose name matches a
52//     struct field name with an associated tag containing ",attr" or
53//     the explicit name in a struct field tag of the form "name,attr",
54//     Unmarshal records the attribute value in that field.
55//
56//   - If the XML element has an attribute not handled by the previous
57//     rule and the struct has a field with an associated tag containing
58//     ",any,attr", Unmarshal records the attribute value in the first
59//     such field.
60//
61//   - If the XML element contains character data, that data is
62//     accumulated in the first struct field that has tag ",chardata".
63//     The struct field may have type []byte or string.
64//     If there is no such field, the character data is discarded.
65//
66//   - If the XML element contains comments, they are accumulated in
67//     the first struct field that has tag ",comment".  The struct
68//     field may have type []byte or string. If there is no such
69//     field, the comments are discarded.
70//
71//   - If the XML element contains a sub-element whose name matches
72//     the prefix of a tag formatted as "a" or "a>b>c", unmarshal
73//     will descend into the XML structure looking for elements with the
74//     given names, and will map the innermost elements to that struct
75//     field. A tag starting with ">" is equivalent to one starting
76//     with the field name followed by ">".
77//
78//   - If the XML element contains a sub-element whose name matches
79//     a struct field's XMLName tag and the struct field has no
80//     explicit name tag as per the previous rule, unmarshal maps
81//     the sub-element to that struct field.
82//
83//   - If the XML element contains a sub-element whose name matches a
84//     field without any mode flags (",attr", ",chardata", etc), Unmarshal
85//     maps the sub-element to that struct field.
86//
87//   - If the XML element contains a sub-element that hasn't matched any
88//     of the above rules and the struct has a field with tag ",any",
89//     unmarshal maps the sub-element to that struct field.
90//
91//   - An anonymous struct field is handled as if the fields of its
92//     value were part of the outer struct.
93//
94//   - A struct field with tag "-" is never unmarshaled into.
95//
96// If Unmarshal encounters a field type that implements the Unmarshaler
97// interface, Unmarshal calls its UnmarshalXML method to produce the value from
98// the XML element.  Otherwise, if the value implements
99// [encoding.TextUnmarshaler], Unmarshal calls that value's UnmarshalText method.
100//
101// Unmarshal maps an XML element to a string or []byte by saving the
102// concatenation of that element's character data in the string or
103// []byte. The saved []byte is never nil.
104//
105// Unmarshal maps an attribute value to a string or []byte by saving
106// the value in the string or slice.
107//
108// Unmarshal maps an attribute value to an [Attr] by saving the attribute,
109// including its name, in the Attr.
110//
111// Unmarshal maps an XML element or attribute value to a slice by
112// extending the length of the slice and mapping the element or attribute
113// to the newly created value.
114//
115// Unmarshal maps an XML element or attribute value to a bool by
116// setting it to the boolean value represented by the string. Whitespace
117// is trimmed and ignored.
118//
119// Unmarshal maps an XML element or attribute value to an integer or
120// floating-point field by setting the field to the result of
121// interpreting the string value in decimal. There is no check for
122// overflow. Whitespace is trimmed and ignored.
123//
124// Unmarshal maps an XML element to a Name by recording the element
125// name.
126//
127// Unmarshal maps an XML element to a pointer by setting the pointer
128// to a freshly allocated value and then mapping the element to that value.
129//
130// A missing element or empty attribute value will be unmarshaled as a zero value.
131// If the field is a slice, a zero value will be appended to the field. Otherwise, the
132// field will be set to its zero value.
133func Unmarshal(data []byte, v any) error {
134	return NewDecoder(bytes.NewReader(data)).Decode(v)
135}
136
137// Decode works like [Unmarshal], except it reads the decoder
138// stream to find the start element.
139func (d *Decoder) Decode(v any) error {
140	return d.DecodeElement(v, nil)
141}
142
143// DecodeElement works like [Unmarshal] except that it takes
144// a pointer to the start XML element to decode into v.
145// It is useful when a client reads some raw XML tokens itself
146// but also wants to defer to [Unmarshal] for some elements.
147func (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, 0)
157}
158
159// An UnmarshalError represents an error in the unmarshaling process.
160type UnmarshalError string
161
162func (e UnmarshalError) Error() string { return string(e) }
163
164// Unmarshaler is the interface implemented by objects that can unmarshal
165// an XML element description of themselves.
166//
167// UnmarshalXML decodes a single XML element
168// beginning with the given start element.
169// If it returns an error, the outer call to Unmarshal stops and
170// returns that error.
171// UnmarshalXML must consume exactly one XML element.
172// One common implementation strategy is to unmarshal into
173// a separate value with a layout matching the expected XML
174// using d.DecodeElement, and then to copy the data from
175// that value into the receiver.
176// Another common strategy is to use d.Token to process the
177// XML object one token at a time.
178// UnmarshalXML may not use d.RawToken.
179type Unmarshaler interface {
180	UnmarshalXML(d *Decoder, start StartElement) error
181}
182
183// UnmarshalerAttr is the interface implemented by objects that can unmarshal
184// an XML attribute description of themselves.
185//
186// UnmarshalXMLAttr decodes a single XML attribute.
187// If it returns an error, the outer call to [Unmarshal] stops and
188// returns that error.
189// UnmarshalXMLAttr is used only for struct fields with the
190// "attr" option in the field tag.
191type UnmarshalerAttr interface {
192	UnmarshalXMLAttr(attr Attr) error
193}
194
195// receiverType returns the receiver type to use in an expression like "%s.MethodName".
196func 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// unmarshalInterface unmarshals a single XML element into val.
205// start is the opening tag of the element.
206func (d *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error {
207	// Record that decoder must stop at end tag corresponding to start.
208	d.pushEOF()
209
210	d.unmarshalDepth++
211	err := val.UnmarshalXML(d, *start)
212	d.unmarshalDepth--
213	if err != nil {
214		d.popEOF()
215		return err
216	}
217
218	if !d.popEOF() {
219		return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(val), start.Name.Local)
220	}
221
222	return nil
223}
224
225// unmarshalTextInterface unmarshals a single XML element into val.
226// The chardata contained in the element (but not its children)
227// is passed to the text unmarshaler.
228func (d *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error {
229	var buf []byte
230	depth := 1
231	for depth > 0 {
232		t, err := d.Token()
233		if err != nil {
234			return err
235		}
236		switch t := t.(type) {
237		case CharData:
238			if depth == 1 {
239				buf = append(buf, t...)
240			}
241		case StartElement:
242			depth++
243		case EndElement:
244			depth--
245		}
246	}
247	return val.UnmarshalText(buf)
248}
249
250// unmarshalAttr unmarshals a single XML attribute into val.
251func (d *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
252	if val.Kind() == reflect.Pointer {
253		if val.IsNil() {
254			val.Set(reflect.New(val.Type().Elem()))
255		}
256		val = val.Elem()
257	}
258	if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) {
259		// This is an unmarshaler with a non-pointer receiver,
260		// so it's likely to be incorrect, but we do what we're told.
261		return val.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr)
262	}
263	if val.CanAddr() {
264		pv := val.Addr()
265		if pv.CanInterface() && pv.Type().Implements(unmarshalerAttrType) {
266			return pv.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr)
267		}
268	}
269
270	// Not an UnmarshalerAttr; try encoding.TextUnmarshaler.
271	if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
272		// This is an unmarshaler with a non-pointer receiver,
273		// so it's likely to be incorrect, but we do what we're told.
274		return val.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value))
275	}
276	if val.CanAddr() {
277		pv := val.Addr()
278		if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
279			return pv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value))
280		}
281	}
282
283	if val.Type().Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
284		// Slice of element values.
285		// Grow slice.
286		n := val.Len()
287		val.Grow(1)
288		val.SetLen(n + 1)
289
290		// Recur to read element into slice.
291		if err := d.unmarshalAttr(val.Index(n), attr); err != nil {
292			val.SetLen(n)
293			return err
294		}
295		return nil
296	}
297
298	if val.Type() == attrType {
299		val.Set(reflect.ValueOf(attr))
300		return nil
301	}
302
303	return copyValue(val, []byte(attr.Value))
304}
305
306var (
307	attrType            = reflect.TypeFor[Attr]()
308	unmarshalerType     = reflect.TypeFor[Unmarshaler]()
309	unmarshalerAttrType = reflect.TypeFor[UnmarshalerAttr]()
310	textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]()
311)
312
313const (
314	maxUnmarshalDepth     = 10000
315	maxUnmarshalDepthWasm = 5000 // go.dev/issue/56498
316)
317
318var errUnmarshalDepth = errors.New("exceeded max depth")
319
320// Unmarshal a single XML element into val.
321func (d *Decoder) unmarshal(val reflect.Value, start *StartElement, depth int) error {
322	if depth >= maxUnmarshalDepth || runtime.GOARCH == "wasm" && depth >= maxUnmarshalDepthWasm {
323		return errUnmarshalDepth
324	}
325	// Find start element if we need it.
326	if start == nil {
327		for {
328			tok, err := d.Token()
329			if err != nil {
330				return err
331			}
332			if t, ok := tok.(StartElement); ok {
333				start = &t
334				break
335			}
336		}
337	}
338
339	// Load value from interface, but only if the result will be
340	// usefully addressable.
341	if val.Kind() == reflect.Interface && !val.IsNil() {
342		e := val.Elem()
343		if e.Kind() == reflect.Pointer && !e.IsNil() {
344			val = e
345		}
346	}
347
348	if val.Kind() == reflect.Pointer {
349		if val.IsNil() {
350			val.Set(reflect.New(val.Type().Elem()))
351		}
352		val = val.Elem()
353	}
354
355	if val.CanInterface() && val.Type().Implements(unmarshalerType) {
356		// This is an unmarshaler with a non-pointer receiver,
357		// so it's likely to be incorrect, but we do what we're told.
358		return d.unmarshalInterface(val.Interface().(Unmarshaler), start)
359	}
360
361	if val.CanAddr() {
362		pv := val.Addr()
363		if pv.CanInterface() && pv.Type().Implements(unmarshalerType) {
364			return d.unmarshalInterface(pv.Interface().(Unmarshaler), start)
365		}
366	}
367
368	if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
369		return d.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler))
370	}
371
372	if val.CanAddr() {
373		pv := val.Addr()
374		if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
375			return d.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler))
376		}
377	}
378
379	var (
380		data         []byte
381		saveData     reflect.Value
382		comment      []byte
383		saveComment  reflect.Value
384		saveXML      reflect.Value
385		saveXMLIndex int
386		saveXMLData  []byte
387		saveAny      reflect.Value
388		sv           reflect.Value
389		tinfo        *typeInfo
390		err          error
391	)
392
393	switch v := val; v.Kind() {
394	default:
395		return errors.New("unknown type " + v.Type().String())
396
397	case reflect.Interface:
398		// TODO: For now, simply ignore the field. In the near
399		//       future we may choose to unmarshal the start
400		//       element on it, if not nil.
401		return d.Skip()
402
403	case reflect.Slice:
404		typ := v.Type()
405		if typ.Elem().Kind() == reflect.Uint8 {
406			// []byte
407			saveData = v
408			break
409		}
410
411		// Slice of element values.
412		// Grow slice.
413		n := v.Len()
414		v.Grow(1)
415		v.SetLen(n + 1)
416
417		// Recur to read element into slice.
418		if err := d.unmarshal(v.Index(n), start, depth+1); err != nil {
419			v.SetLen(n)
420			return err
421		}
422		return nil
423
424	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:
425		saveData = v
426
427	case reflect.Struct:
428		typ := v.Type()
429		if typ == nameType {
430			v.Set(reflect.ValueOf(start.Name))
431			break
432		}
433
434		sv = v
435		tinfo, err = getTypeInfo(typ)
436		if err != nil {
437			return err
438		}
439
440		// Validate and assign element name.
441		if tinfo.xmlname != nil {
442			finfo := tinfo.xmlname
443			if finfo.name != "" && finfo.name != start.Name.Local {
444				return UnmarshalError("expected element type <" + finfo.name + "> but have <" + start.Name.Local + ">")
445			}
446			if finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
447				e := "expected element <" + finfo.name + "> in name space " + finfo.xmlns + " but have "
448				if start.Name.Space == "" {
449					e += "no name space"
450				} else {
451					e += start.Name.Space
452				}
453				return UnmarshalError(e)
454			}
455			fv := finfo.value(sv, initNilPointers)
456			if _, ok := fv.Interface().(Name); ok {
457				fv.Set(reflect.ValueOf(start.Name))
458			}
459		}
460
461		// Assign attributes.
462		for _, a := range start.Attr {
463			handled := false
464			any := -1
465			for i := range tinfo.fields {
466				finfo := &tinfo.fields[i]
467				switch finfo.flags & fMode {
468				case fAttr:
469					strv := finfo.value(sv, initNilPointers)
470					if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
471						if err := d.unmarshalAttr(strv, a); err != nil {
472							return err
473						}
474						handled = true
475					}
476
477				case fAny | fAttr:
478					if any == -1 {
479						any = i
480					}
481				}
482			}
483			if !handled && any >= 0 {
484				finfo := &tinfo.fields[any]
485				strv := finfo.value(sv, initNilPointers)
486				if err := d.unmarshalAttr(strv, a); err != nil {
487					return err
488				}
489			}
490		}
491
492		// Determine whether we need to save character data or comments.
493		for i := range tinfo.fields {
494			finfo := &tinfo.fields[i]
495			switch finfo.flags & fMode {
496			case fCDATA, fCharData:
497				if !saveData.IsValid() {
498					saveData = finfo.value(sv, initNilPointers)
499				}
500
501			case fComment:
502				if !saveComment.IsValid() {
503					saveComment = finfo.value(sv, initNilPointers)
504				}
505
506			case fAny, fAny | fElement:
507				if !saveAny.IsValid() {
508					saveAny = finfo.value(sv, initNilPointers)
509				}
510
511			case fInnerXML:
512				if !saveXML.IsValid() {
513					saveXML = finfo.value(sv, initNilPointers)
514					if d.saved == nil {
515						saveXMLIndex = 0
516						d.saved = new(bytes.Buffer)
517					} else {
518						saveXMLIndex = d.savedOffset()
519					}
520				}
521			}
522		}
523	}
524
525	// Find end element.
526	// Process sub-elements along the way.
527Loop:
528	for {
529		var savedOffset int
530		if saveXML.IsValid() {
531			savedOffset = d.savedOffset()
532		}
533		tok, err := d.Token()
534		if err != nil {
535			return err
536		}
537		switch t := tok.(type) {
538		case StartElement:
539			consumed := false
540			if sv.IsValid() {
541				// unmarshalPath can call unmarshal, so we need to pass the depth through so that
542				// we can continue to enforce the maximum recursion limit.
543				consumed, err = d.unmarshalPath(tinfo, sv, nil, &t, depth)
544				if err != nil {
545					return err
546				}
547				if !consumed && saveAny.IsValid() {
548					consumed = true
549					if err := d.unmarshal(saveAny, &t, depth+1); err != nil {
550						return err
551					}
552				}
553			}
554			if !consumed {
555				if err := d.Skip(); err != nil {
556					return err
557				}
558			}
559
560		case EndElement:
561			if saveXML.IsValid() {
562				saveXMLData = d.saved.Bytes()[saveXMLIndex:savedOffset]
563				if saveXMLIndex == 0 {
564					d.saved = nil
565				}
566			}
567			break Loop
568
569		case CharData:
570			if saveData.IsValid() {
571				data = append(data, t...)
572			}
573
574		case Comment:
575			if saveComment.IsValid() {
576				comment = append(comment, t...)
577			}
578		}
579	}
580
581	if saveData.IsValid() && saveData.CanInterface() && saveData.Type().Implements(textUnmarshalerType) {
582		if err := saveData.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
583			return err
584		}
585		saveData = reflect.Value{}
586	}
587
588	if saveData.IsValid() && saveData.CanAddr() {
589		pv := saveData.Addr()
590		if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
591			if err := pv.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
592				return err
593			}
594			saveData = reflect.Value{}
595		}
596	}
597
598	if err := copyValue(saveData, data); err != nil {
599		return err
600	}
601
602	switch t := saveComment; t.Kind() {
603	case reflect.String:
604		t.SetString(string(comment))
605	case reflect.Slice:
606		t.Set(reflect.ValueOf(comment))
607	}
608
609	switch t := saveXML; t.Kind() {
610	case reflect.String:
611		t.SetString(string(saveXMLData))
612	case reflect.Slice:
613		if t.Type().Elem().Kind() == reflect.Uint8 {
614			t.Set(reflect.ValueOf(saveXMLData))
615		}
616	}
617
618	return nil
619}
620
621func copyValue(dst reflect.Value, src []byte) (err error) {
622	dst0 := dst
623
624	if dst.Kind() == reflect.Pointer {
625		if dst.IsNil() {
626			dst.Set(reflect.New(dst.Type().Elem()))
627		}
628		dst = dst.Elem()
629	}
630
631	// Save accumulated data.
632	switch dst.Kind() {
633	case reflect.Invalid:
634		// Probably a comment.
635	default:
636		return errors.New("cannot unmarshal into " + dst0.Type().String())
637	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
638		if len(src) == 0 {
639			dst.SetInt(0)
640			return nil
641		}
642		itmp, err := strconv.ParseInt(strings.TrimSpace(string(src)), 10, dst.Type().Bits())
643		if err != nil {
644			return err
645		}
646		dst.SetInt(itmp)
647	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
648		if len(src) == 0 {
649			dst.SetUint(0)
650			return nil
651		}
652		utmp, err := strconv.ParseUint(strings.TrimSpace(string(src)), 10, dst.Type().Bits())
653		if err != nil {
654			return err
655		}
656		dst.SetUint(utmp)
657	case reflect.Float32, reflect.Float64:
658		if len(src) == 0 {
659			dst.SetFloat(0)
660			return nil
661		}
662		ftmp, err := strconv.ParseFloat(strings.TrimSpace(string(src)), dst.Type().Bits())
663		if err != nil {
664			return err
665		}
666		dst.SetFloat(ftmp)
667	case reflect.Bool:
668		if len(src) == 0 {
669			dst.SetBool(false)
670			return nil
671		}
672		value, err := strconv.ParseBool(strings.TrimSpace(string(src)))
673		if err != nil {
674			return err
675		}
676		dst.SetBool(value)
677	case reflect.String:
678		dst.SetString(string(src))
679	case reflect.Slice:
680		if len(src) == 0 {
681			// non-nil to flag presence
682			src = []byte{}
683		}
684		dst.SetBytes(src)
685	}
686	return nil
687}
688
689// unmarshalPath walks down an XML structure looking for wanted
690// paths, and calls unmarshal on them.
691// The consumed result tells whether XML elements have been consumed
692// from the Decoder until start's matching end element, or if it's
693// still untouched because start is uninteresting for sv's fields.
694func (d *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement, depth int) (consumed bool, err error) {
695	recurse := false
696Loop:
697	for i := range tinfo.fields {
698		finfo := &tinfo.fields[i]
699		if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
700			continue
701		}
702		for j := range parents {
703			if parents[j] != finfo.parents[j] {
704				continue Loop
705			}
706		}
707		if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local {
708			// It's a perfect match, unmarshal the field.
709			return true, d.unmarshal(finfo.value(sv, initNilPointers), start, depth+1)
710		}
711		if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local {
712			// It's a prefix for the field. Break and recurse
713			// since it's not ok for one field path to be itself
714			// the prefix for another field path.
715			recurse = true
716
717			// We can reuse the same slice as long as we
718			// don't try to append to it.
719			parents = finfo.parents[:len(parents)+1]
720			break
721		}
722	}
723	if !recurse {
724		// We have no business with this element.
725		return false, nil
726	}
727	// The element is not a perfect match for any field, but one
728	// or more fields have the path to this element as a parent
729	// prefix. Recurse and attempt to match these.
730	for {
731		var tok Token
732		tok, err = d.Token()
733		if err != nil {
734			return true, err
735		}
736		switch t := tok.(type) {
737		case StartElement:
738			// the recursion depth of unmarshalPath is limited to the path length specified
739			// by the struct field tag, so we don't increment the depth here.
740			consumed2, err := d.unmarshalPath(tinfo, sv, parents, &t, depth)
741			if err != nil {
742				return true, err
743			}
744			if !consumed2 {
745				if err := d.Skip(); err != nil {
746					return true, err
747				}
748			}
749		case EndElement:
750			return true, nil
751		}
752	}
753}
754
755// Skip reads tokens until it has consumed the end element
756// matching the most recent start element already consumed,
757// skipping nested structures.
758// It returns nil if it finds an end element matching the start
759// element; otherwise it returns an error describing the problem.
760func (d *Decoder) Skip() error {
761	var depth int64
762	for {
763		tok, err := d.Token()
764		if err != nil {
765			return err
766		}
767		switch tok.(type) {
768		case StartElement:
769			depth++
770		case EndElement:
771			if depth == 0 {
772				return nil
773			}
774			depth--
775		}
776	}
777}
778