func (p *Decoder) unmarshal(val reflect.Value, start gokoxml.Node) error { // Find first xml node. if start == nil { start = p.doc.Root().XmlNode } // Unpacks a pointer if pv := val; pv.Kind() == reflect.Ptr { if pv.IsNil() { pv.Set(reflect.New(pv.Type().Elem())) } val = pv.Elem() } var ( sv reflect.Value tinfo *typeInfo err error ) switch v := val; v.Kind() { default: return errors.New("unknown type " + v.Type().String()) // TODO: Implement this once i understand Skip() // case reflect.Interface: // return p.Skip() case reflect.Slice: typ := v.Type() if typ.Elem().Kind() == reflect.Uint8 { // []byte if err := copyValue(v, start.Content()); err != nil { return err } break } // Slice of element values. // Grow slice. n := v.Len() if n >= v.Cap() { ncap := 2 * n if ncap < 4 { ncap = 4 } new := reflect.MakeSlice(typ, n, ncap) reflect.Copy(new, v) v.Set(new) } v.SetLen(n + 1) // Recur to read element into slice. if err := p.unmarshal(v.Index(n), start); err != nil { v.SetLen(n) return err } return nil 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: if err := copyValue(v, start.Content()); err != nil { return err } case reflect.Struct: typ := v.Type() if typ == nameType { v.Set(reflect.ValueOf(xml.Name{Local: start.Name()})) break } if typ == timeType { if err := copyValue(v, start.Content()); err != nil { return err } break } sv = v tinfo, err = getTypeInfo(typ) if err != nil { return err } // Validate and assign element name. if tinfo.xmlname != nil { // var space string finfo := tinfo.xmlname if finfo.name != "" && finfo.name != start.Name() { return UnmarshalError("expected element type <" + finfo.name + "> but have <" + start.Name() + ">") } fv := sv.FieldByIndex(finfo.idx) if _, ok := fv.Interface().(xml.Name); ok { fv.Set(reflect.ValueOf(xml.Name{Local: start.Name()})) } } var saveComment reflect.Value var doSaveComment = false _ = saveComment for i := range tinfo.fields { finfo := &tinfo.fields[i] switch finfo.flags & fMode { case fAttr: strv := sv.FieldByIndex(finfo.idx) for name, a := range start.Attributes() { if name == finfo.name { copyValue(strv, a.Content()) } } case fCharData: strv := sv.FieldByIndex(finfo.idx) copyValue(strv, start.Content()) case fInnerXml: strv := sv.FieldByIndex(finfo.idx) // TODO: Not sure why i need to call FirstChild() here. copyValue(strv, start.FirstChild().String()) case fComment: if !doSaveComment { doSaveComment = true saveComment = sv.FieldByIndex(finfo.idx) } } } for cur_node := start.FirstChild(); cur_node != nil; cur_node = cur_node.NextSibling() { if sv.IsValid() { if cur_node.NodeType() != gokoxml.XML_ELEMENT_NODE { if doSaveComment && cur_node.NodeType() == gokoxml.XML_COMMENT_NODE { copyValue(saveComment, cur_node.Content()) } continue } err = p.unmarshalPath(tinfo, sv, nil, cur_node) if err != nil { return err } } } } // switch v := val; v.Kind() { return nil }