func enc_struct(val *reflect.StructValue, typ *reflect.StructType, buffer *bytes.Buffer) os.Error { buffer.WriteString("{") first := true for i := 0; i < typ.NumField(); i++ { f := typ.Field(i) if f.Tag == "" { continue } tags := strings.Split(f.Tag[3:len(f.Tag)-1], ",", -1) l := buffer.Len() if first { buffer.WriteString(fmt.Sprintf("\"%v\":", tags[1])) } else { buffer.WriteString(fmt.Sprintf(",\"%v\":", tags[1])) } written, err := enc(val.Field(i), f.Type, buffer, tags[2] == "req") if err != nil { return err } if !written { buffer.Truncate(l) } else { first = false } } buffer.WriteString("}") return nil }
func compileStruct(t *reflect.StructType) map[string]reflect.StructField { m := make(map[string]reflect.StructField) for i := 0; i < t.NumField(); i++ { f := t.Field(i) if f.PkgPath != "" { // ignore if not exported continue } name := f.Name if f.Tag != "" { name = f.Tag } m[name] = f } return m }
func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer, p uintptr, indir int) os.Error { if indir > 0 { up := unsafe.Pointer(p) if indir > 1 { up = decIndirect(up, indir) } if *(*unsafe.Pointer)(up) == nil { // Allocate object by making a slice of bytes and recording the // address of the beginning of the array. TODO(rsc). b := make([]byte, rtyp.Size()) *(*unsafe.Pointer)(up) = unsafe.Pointer(&b[0]) } p = *(*uintptr)(up) } state := newDecodeState(b) state.fieldnum = -1 basep := p for state.err == nil { delta := int(decodeUint(state)) if delta < 0 { state.err = os.ErrorString("gob decode: corrupted data: negative delta") break } if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum break } fieldnum := state.fieldnum + delta if fieldnum >= len(engine.instr) { state.err = errRange break } instr := &engine.instr[fieldnum] p := unsafe.Pointer(basep + instr.offset) if instr.indir > 1 { p = decIndirect(p, instr.indir) } instr.op(instr, state, p) state.fieldnum = fieldnum } return state.err }
func dec_struct(val *reflect.StructValue, typ *reflect.StructType, json map[string]interface{}) os.Error { for i := 0; i < typ.NumField(); i++ { f := typ.Field(i) if f.Tag == "" { continue } tags := strings.Split(f.Tag[3:len(f.Tag)-1], ",", -1) j, ok := json[tags[1]] if !ok { if tags[2] == "req" { return os.NewError("Field " + f.Name + " is missing") } continue } err := dec(val.Field(i), f.Type, j) if err != nil { return err } } return nil }
func attributes(m interface{}) (map[string]reflect.Type, reflect.Type) { var st *reflect.StructType var typ reflect.Type if _, ok := reflect.Typeof(m).(*reflect.PtrType); ok { typ = reflect.Typeof(m).(*reflect.PtrType).Elem() } else { typ = reflect.Typeof(m) } st = typ.(*reflect.StructType) //fmt.Println(st.NumField()) ret := make(map[string]reflect.Type) for i := 0; i < st.NumField(); i++ { p := st.Field(i) //fmt.Println(p.Name) if !p.Anonymous { ret[p.Name] = p.Type } } return ret, typ }
// 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, ok := val.(*reflect.PtrValue); ok { if pv.Get() == 0 { zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()) pv.PointTo(zv) val = zv } else { val = pv.Elem() } } var ( data []byte saveData reflect.Value comment []byte saveComment reflect.Value sv *reflect.StructValue styp *reflect.StructType ) switch v := val.(type) { default: return os.ErrorString("unknown type " + v.Type().String()) case *reflect.BoolValue: v.Set(true) case *reflect.SliceValue: typ := v.Type().(*reflect.SliceType) if _, ok := typ.Elem().(*reflect.Uint8Type); ok { // []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.ArrayCopy(new, v) v.Set(new) } v.SetLen(n + 1) // Recur to read element into slice. if err := p.unmarshal(v.Elem(n), start); err != nil { v.SetLen(n) return err } return nil case *reflect.StringValue, *reflect.IntValue, *reflect.UintValue, *reflect.UintptrValue, *reflect.Int8Value, *reflect.Int16Value, *reflect.Int32Value, *reflect.Int64Value, *reflect.Uint8Value, *reflect.Uint16Value, *reflect.Uint32Value, *reflect.Uint64Value, *reflect.FloatValue, *reflect.Float32Value, *reflect.Float64Value: saveData = v case *reflect.StructValue: if _, ok := v.Interface().(Name); ok { v.Set(reflect.NewValue(start.Name).(*reflect.StructValue)) break } sv = v typ := sv.Type().(*reflect.StructType) styp = typ // Assign name. if f, ok := typ.FieldByName("XMLName"); ok { // Validate element name. if f.Tag != "" { tag := f.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 { return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name") } v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue)) } // 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 { case "attr": strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue) if !ok { return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string") } // Look for attribute. val := "" k := strings.ToLower(f.Name) for _, a := range start.Attr { if fieldName(a.Name.Local) == k { val = a.Value break } } strv.Set(val) case "comment": if saveComment == nil { saveComment = sv.FieldByIndex(f.Index) } case "chardata": if saveData == nil { saveData = sv.FieldByIndex(f.Index) } } } } // Find end element. // Process sub-elements along the way. Loop: for { tok, err := p.Token() if err != nil { return err } switch t := tok.(type) { case StartElement: // Sub-element. // Look up by tag name. // If that fails, fall back to mop-up field named "Any". if sv != nil { k := fieldName(t.Name.Local) any := -1 for i, n := 0, styp.NumField(); i < n; i++ { f := styp.Field(i) if strings.ToLower(f.Name) == k { if err := p.unmarshal(sv.FieldByIndex(f.Index), &t); err != nil { return err } continue Loop } if any < 0 && f.Name == "Any" { any = i } } if any >= 0 { if err := p.unmarshal(sv.FieldByIndex(styp.Field(any).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: break Loop case CharData: if saveData != nil { data = bytes.Add(data, t) } case Comment: if saveComment != nil { comment = bytes.Add(comment, t) } } } var err os.Error // Helper functions for integer and unsigned integer conversions var itmp int64 getInt64 := func() bool { itmp, err = strconv.Atoi64(string(data)) // TODO: should check sizes return err == nil } var utmp uint64 getUint64 := func() bool { utmp, err = strconv.Atoui64(string(data)) // TODO: check for overflow? return err == nil } var ftmp float64 getFloat64 := func() bool { ftmp, err = strconv.Atof64(string(data)) // TODO: check for overflow? return err == nil } // Save accumulated data and comments switch t := saveData.(type) { case nil: // Probably a comment, handled below default: return os.ErrorString("cannot happen: unknown type " + t.Type().String()) case *reflect.IntValue: if !getInt64() { return err } t.Set(int(itmp)) case *reflect.Int8Value: if !getInt64() { return err } t.Set(int8(itmp)) case *reflect.Int16Value: if !getInt64() { return err } t.Set(int16(itmp)) case *reflect.Int32Value: if !getInt64() { return err } t.Set(int32(itmp)) case *reflect.Int64Value: if !getInt64() { return err } t.Set(itmp) case *reflect.UintValue: if !getUint64() { return err } t.Set(uint(utmp)) case *reflect.Uint8Value: if !getUint64() { return err } t.Set(uint8(utmp)) case *reflect.Uint16Value: if !getUint64() { return err } t.Set(uint16(utmp)) case *reflect.Uint32Value: if !getUint64() { return err } t.Set(uint32(utmp)) case *reflect.Uint64Value: if !getUint64() { return err } t.Set(utmp) case *reflect.UintptrValue: if !getUint64() { return err } t.Set(uintptr(utmp)) case *reflect.FloatValue: if !getFloat64() { return err } t.Set(float(ftmp)) case *reflect.Float32Value: if !getFloat64() { return err } t.Set(float32(ftmp)) case *reflect.Float64Value: if !getFloat64() { return err } t.Set(ftmp) case *reflect.StringValue: t.Set(string(data)) case *reflect.SliceValue: t.Set(reflect.NewValue(data).(*reflect.SliceValue)) } switch t := saveComment.(type) { case *reflect.StringValue: t.Set(string(comment)) case *reflect.SliceValue: t.Set(reflect.NewValue(comment).(*reflect.SliceValue)) } return nil }
// 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, ok := val.(*reflect.PtrValue); ok { if pv.Get() == 0 { zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()) pv.PointTo(zv) val = zv } else { val = pv.Elem() } } var ( data []byte saveData reflect.Value comment []byte saveComment reflect.Value saveXML reflect.Value saveXMLIndex int saveXMLData []byte sv *reflect.StructValue styp *reflect.StructType fieldPaths map[string]pathInfo ) switch v := val.(type) { default: return os.ErrorString("unknown type " + v.Type().String()) case *reflect.SliceValue: typ := v.Type().(*reflect.SliceType) 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.Elem(n), start); err != nil { v.SetLen(n) return err } return nil case *reflect.BoolValue, *reflect.FloatValue, *reflect.IntValue, *reflect.UintValue, *reflect.StringValue: saveData = v case *reflect.StructValue: if _, ok := v.Interface().(Name); ok { v.Set(reflect.NewValue(start.Name).(*reflect.StructValue)) break } sv = v typ := sv.Type().(*reflect.StructType) styp = typ // Assign name. if f, ok := typ.FieldByName("XMLName"); ok { // Validate element name. if f.Tag != "" { tag := f.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 { return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name") } v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue)) } // 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 { case "attr": strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue) if !ok { return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string") } // Look for attribute. val := "" k := strings.ToLower(f.Name) for _, a := range start.Attr { if fieldName(a.Name.Local) == k { val = a.Value break } } strv.Set(val) case "comment": if saveComment == nil { saveComment = sv.FieldByIndex(f.Index) } case "chardata": if saveData == nil { saveData = sv.FieldByIndex(f.Index) } case "innerxml": if saveXML == nil { saveXML = sv.FieldByIndex(f.Index) if p.saved == nil { saveXMLIndex = 0 p.saved = new(bytes.Buffer) } else { saveXMLIndex = p.savedOffset() } } default: if strings.Contains(f.Tag, ">") { if fieldPaths == nil { fieldPaths = make(map[string]pathInfo) } path := strings.ToLower(f.Tag) if strings.HasPrefix(f.Tag, ">") { path = strings.ToLower(f.Name) + path } if strings.HasSuffix(f.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 != nil { 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 != nil { 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 != nil { saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset] if saveXMLIndex == 0 { p.saved = nil } } break Loop case CharData: if saveData != nil { data = append(data, t...) } case Comment: if saveComment != nil { comment = append(comment, t...) } } } var err os.Error // Helper functions for integer and unsigned integer conversions var itmp int64 getInt64 := func() bool { itmp, err = strconv.Atoi64(string(data)) // TODO: should check sizes return err == nil } var utmp uint64 getUint64 := func() bool { utmp, err = strconv.Atoui64(string(data)) // TODO: check for overflow? return err == nil } var ftmp float64 getFloat64 := func() bool { ftmp, err = strconv.Atof64(string(data)) // TODO: check for overflow? return err == nil } // Save accumulated data and comments switch t := saveData.(type) { case nil: // Probably a comment, handled below default: return os.ErrorString("cannot happen: unknown type " + t.Type().String()) case *reflect.IntValue: if !getInt64() { return err } t.Set(itmp) case *reflect.UintValue: if !getUint64() { return err } t.Set(utmp) case *reflect.FloatValue: if !getFloat64() { return err } t.Set(ftmp) case *reflect.BoolValue: value, err := strconv.Atob(strings.TrimSpace(string(data))) if err != nil { return err } t.Set(value) case *reflect.StringValue: t.Set(string(data)) case *reflect.SliceValue: t.Set(reflect.NewValue(data).(*reflect.SliceValue)) } switch t := saveComment.(type) { case *reflect.StringValue: t.Set(string(comment)) case *reflect.SliceValue: t.Set(reflect.NewValue(comment).(*reflect.SliceValue)) } switch t := saveXML.(type) { case *reflect.StringValue: t.Set(string(saveXMLData)) case *reflect.SliceValue: t.Set(reflect.NewValue(saveXMLData).(*reflect.SliceValue)) } return nil }