func columnToFieldIndex(m *DbMap, t reflect.Type, cols []string) ([][]int, error) { colToFieldIndex := make([][]int, len(cols)) // check if type t is a mapped table - if so we'll // check the table for column aliasing below tableMapped := false table := tableOrNil(m, t) if table != nil { tableMapped = true } // Loop over column names and find field in i to bind to // based on column name. all returned columns must match // a field in the i struct missingColNames := []string{} for x := range cols { colName := strings.ToLower(cols[x]) field, found := t.FieldByNameFunc(func(fieldName string) bool { field, _ := t.FieldByName(fieldName) cArguments := strings.Split(field.Tag.Get("db"), ",") fieldName = cArguments[0] if fieldName == "-" { return false } else if fieldName == "" { fieldName = field.Name } if tableMapped { colMap := colMapOrNil(table, fieldName) if colMap != nil { fieldName = colMap.ColumnName } } return colName == strings.ToLower(fieldName) }) if found { colToFieldIndex[x] = field.Index } if colToFieldIndex[x] == nil { missingColNames = append(missingColNames, colName) } } if len(missingColNames) > 0 { return colToFieldIndex, &NoFieldInTypeError{ TypeName: t.Name(), MissingColNames: missingColNames, } } return colToFieldIndex, nil }
func columnToFieldIndex(m *DbMap, t reflect.Type, cols []string) ([][]int, error) { colToFieldIndex := make([][]int, len(cols)) // check if type t is a mapped table - if so we'll // check the table for column aliasing below tableMapped := false table := tableOrNil(m, t) if table != nil { tableMapped = true } // Loop over column names and find field in i to bind to // based on column name. all returned columns must match // a field in the i struct for x := range cols { colName := strings.ToLower(cols[x]) field, found := t.FieldByNameFunc(func(fieldName string) bool { field, _ := t.FieldByName(fieldName) fieldName = field.Tag.Get("db") if fieldName == "-" { return false } else if fieldName == "" { fieldName = field.Name } if tableMapped { colMap := colMapOrNil(table, fieldName) if colMap != nil { fieldName = colMap.ColumnName } } return colName == strings.ToLower(fieldName) }) if found { colToFieldIndex[x] = field.Index } if colToFieldIndex[x] == nil { return nil, fmt.Errorf("gorp: No field %s in type %s", colName, t.Name()) } } return colToFieldIndex, nil }
func makeColToFieldIndex(t reflect.Type, cols []string) [][]int { var colToFieldIndex = make([][]int, len(cols)) for x := range cols { colName := strings.ToLower(cols[x]) field, found := t.FieldByNameFunc(func(fieldName string) bool { field, _ := t.FieldByName(fieldName) tags := strings.Split(field.Tag.Get("db"), ", ") dbNameFromTag := tags[0] if dbNameFromTag == "" { return strings.ToLower(field.Name) == colName } return colName == dbNameFromTag }) if found { colToFieldIndex[x] = field.Index } } return colToFieldIndex }
// Unmarshal a single XML element into val. func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error { // Find start element if we need it. if start == nil { for { tok, err := p.Token() if err != nil { return err } if t, ok := tok.(StartElement); ok { start = &t break } } } if pv := val; pv.Kind() == reflect.Ptr { if pv.IsNil() { pv.Set(reflect.New(pv.Type().Elem())) } val = pv.Elem() } var ( data []byte saveData reflect.Value comment []byte saveComment reflect.Value saveXML reflect.Value saveXMLIndex int saveXMLData []byte sv reflect.Value styp reflect.Type fieldPaths map[string]pathInfo ) switch v := val; v.Kind() { default: return os.NewError("unknown type " + v.Type().String()) case reflect.Slice: typ := v.Type() if typ.Elem().Kind() == reflect.Uint8 { // []byte saveData = v 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: saveData = v case reflect.Struct: if _, ok := v.Interface().(Name); ok { v.Set(reflect.ValueOf(start.Name)) break } sv = v typ := sv.Type() styp = typ // Assign name. if f, ok := typ.FieldByName("XMLName"); ok { // Validate element name. if tag := f.Tag.Get("xml"); tag != "" { ns := "" i := strings.LastIndex(tag, " ") if i >= 0 { ns, tag = tag[0:i], tag[i+1:] } if tag != start.Name.Local { return UnmarshalError("expected element type <" + tag + "> but have <" + start.Name.Local + ">") } if ns != "" && ns != start.Name.Space { e := "expected element <" + tag + "> in name space " + ns + " but have " if start.Name.Space == "" { e += "no name space" } else { e += start.Name.Space } return UnmarshalError(e) } } // Save v := sv.FieldByIndex(f.Index) if _, ok := v.Interface().(Name); ok { v.Set(reflect.ValueOf(start.Name)) } } // Assign attributes. // Also, determine whether we need to save character data or comments. for i, n := 0, typ.NumField(); i < n; i++ { f := typ.Field(i) switch f.Tag.Get("xml") { case "attr": strv := sv.FieldByIndex(f.Index) // Look for attribute. val := "" k := strings.ToLower(f.Name) for _, a := range start.Attr { if fieldName(a.Name.Local) == k { val = a.Value break } } copyValue(strv, []byte(val)) case "comment": if !saveComment.IsValid() { saveComment = sv.FieldByIndex(f.Index) } case "chardata": if !saveData.IsValid() { saveData = sv.FieldByIndex(f.Index) } case "innerxml": if !saveXML.IsValid() { saveXML = sv.FieldByIndex(f.Index) if p.saved == nil { saveXMLIndex = 0 p.saved = new(bytes.Buffer) } else { saveXMLIndex = p.savedOffset() } } default: if tag := f.Tag.Get("xml"); strings.Contains(tag, ">") { if fieldPaths == nil { fieldPaths = make(map[string]pathInfo) } path := strings.ToLower(tag) if strings.HasPrefix(tag, ">") { path = strings.ToLower(f.Name) + path } if strings.HasSuffix(tag, ">") { path = path[:len(path)-1] } err := addFieldPath(sv, fieldPaths, path, f.Index) if err != nil { return err } } } } } // Find end element. // Process sub-elements along the way. Loop: for { var savedOffset int if saveXML.IsValid() { savedOffset = p.savedOffset() } tok, err := p.Token() if err != nil { return err } switch t := tok.(type) { case StartElement: // Sub-element. // Look up by tag name. if sv.IsValid() { k := fieldName(t.Name.Local) if fieldPaths != nil { if _, found := fieldPaths[k]; found { if err := p.unmarshalPaths(sv, fieldPaths, k, &t); err != nil { return err } continue Loop } } match := func(s string) bool { // check if the name matches ignoring case if strings.ToLower(s) != k { return false } // now check that it's public c, _ := utf8.DecodeRuneInString(s) return unicode.IsUpper(c) } f, found := styp.FieldByNameFunc(match) if !found { // fall back to mop-up field named "Any" f, found = styp.FieldByName("Any") } if found { if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil { return err } continue Loop } } // Not saving sub-element but still have to skip over it. if err := p.Skip(); err != nil { return err } case EndElement: if saveXML.IsValid() { saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset] if saveXMLIndex == 0 { p.saved = nil } } break Loop case CharData: if saveData.IsValid() { data = append(data, t...) } case Comment: if saveComment.IsValid() { comment = append(comment, t...) } } } if err := copyValue(saveData, data); err != nil { return err } switch t := saveComment; t.Kind() { case reflect.String: t.SetString(string(comment)) case reflect.Slice: t.Set(reflect.ValueOf(comment)) } switch t := saveXML; t.Kind() { case reflect.String: t.SetString(string(saveXMLData)) case reflect.Slice: t.Set(reflect.ValueOf(saveXMLData)) } return nil }