unmarshalPath walks down an XML structure looking for wanted paths, and calls unmarshal on them. The consumed result tells whether XML elements have been consumed from the Decoder until start's matching end element, or if it's still untouched because start is uninteresting for sv's fields.
(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement, depth int)
| 706 | // from the Decoder until start's matching end element, or if it's |
| 707 | // still untouched because start is uninteresting for sv's fields. |
| 708 | func (d *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement, depth int) (consumed bool, err error) { |
| 709 | recurse := false |
| 710 | Loop: |
| 711 | for i := range tinfo.fields { |
| 712 | finfo := &tinfo.fields[i] |
| 713 | if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space { |
| 714 | continue |
| 715 | } |
| 716 | for j := range parents { |
| 717 | if parents[j] != finfo.parents[j] { |
| 718 | continue Loop |
| 719 | } |
| 720 | } |
| 721 | if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local { |
| 722 | // It's a perfect match, unmarshal the field. |
| 723 | return true, d.unmarshal(finfo.value(sv, initNilPointers), start, depth+1) |
| 724 | } |
| 725 | if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local { |
| 726 | // It's a prefix for the field. Break and recurse |
| 727 | // since it's not ok for one field path to be itself |
| 728 | // the prefix for another field path. |
| 729 | recurse = true |
| 730 | |
| 731 | // We can reuse the same slice as long as we |
| 732 | // don't try to append to it. |
| 733 | parents = finfo.parents[:len(parents)+1] |
| 734 | break |
| 735 | } |
| 736 | } |
| 737 | if !recurse { |
| 738 | // We have no business with this element. |
| 739 | return false, nil |
| 740 | } |
| 741 | // The element is not a perfect match for any field, but one |
| 742 | // or more fields have the path to this element as a parent |
| 743 | // prefix. Recurse and attempt to match these. |
| 744 | for { |
| 745 | var tok Token |
| 746 | tok, err = d.Token() |
| 747 | if err != nil { |
| 748 | return true, err |
| 749 | } |
| 750 | switch t := tok.(type) { |
| 751 | case StartElement: |
| 752 | // the recursion depth of unmarshalPath is limited to the path length specified |
| 753 | // by the struct field tag, so we don't increment the depth here. |
| 754 | consumed2, err := d.unmarshalPath(tinfo, sv, parents, &t, depth) |
| 755 | if err != nil { |
| 756 | return true, err |
| 757 | } |
| 758 | if !consumed2 { |
| 759 | if err := d.Skip(); err != nil { |
| 760 | return true, err |
| 761 | } |
| 762 | } |
| 763 | case EndElement: |
| 764 | return true, nil |
| 765 | } |