Example #1
0
// Generate a type declaration for the bult-in list values, along with
// marshal/unmarshal methods
func (cfg *Config) genTokenListSpec(t xsd.Builtin) ([]spec, error) {
	cfg.debugf("generating Go source for token list %q", xsd.XMLName(t).Local)
	s := spec{
		name:    strings.ToLower(t.String()),
		expr:    builtinExpr(t),
		xsdType: t,
	}
	marshal, err := gen.Func("MarshalText").
		Receiver("x "+s.name).
		Returns("[]byte", "error").
		Body(`
			return []byte(strings.Join(x, " ")), nil
		`).Decl()

	if err != nil {
		return nil, fmt.Errorf("MarshalText %s: %v", s.name, err)
	}

	unmarshal, err := gen.Func("UnmarshalText").
		Receiver("x " + s.name).
		Args("text []byte").
		Returns("error").
		Body(`
			*x = bytes.Fields(text)
			return nil
		`).Decl()

	if err != nil {
		return nil, fmt.Errorf("UnmarshalText %s: %v", s.name, err)
	}

	s.methods = append(s.methods, marshal, unmarshal)
	return []spec{s}, nil
}
Example #2
0
// Generate a type declaration for the built-in time values, along with
// marshal/unmarshal methods for them.
func (cfg *Config) genTimeSpec(t xsd.Builtin) ([]spec, error) {
	var timespec string
	cfg.debugf("generating Go source for time type %q", xsd.XMLName(t).Local)

	s := spec{
		expr:    ast.NewIdent("time.Time"),
		name:    builtinExpr(t).(*ast.Ident).Name,
		xsdType: t,
	}

	switch t {
	case xsd.GDay:
		timespec = "---02"
	case xsd.GMonth:
		timespec = "--01"
	case xsd.GMonthDay:
		timespec = "--01-02"
	case xsd.GYear:
		timespec = "2006"
	case xsd.GYearMonth:
		timespec = "2006-01"
	case xsd.Time:
		timespec = "15:04:05.999999999"
	case xsd.Date:
		timespec = "2006-01-02"
	case xsd.DateTime:
		timespec = "2006-01-02T15:04:05.999999999"
	}
	unmarshal, err := gen.Func("UnmarshalText").
		Receiver("t *"+s.name).
		Args("text []byte").
		Returns("error").
		Body(`
			return _unmarshalTime(text, (*time.Time)(t), %q)
		`, timespec).Decl()
	if err != nil {
		return nil, fmt.Errorf("could not generate unmarshal function for %s: %v", s.name, err)
	}
	marshal, err := gen.Func("MarshalText").
		Receiver("t *"+s.name).
		Returns("[]byte", "error").
		Body(`
			return []byte((*time.Time)(t).Format(%q)), nil
		`, timespec).Decl()
	if err != nil {
		return nil, fmt.Errorf("could not generate marshal function for %s: %v", s.name, err)
	}
	s.methods = append(s.methods, unmarshal, marshal)
	if helper := cfg.helper("_unmarshalTime"); helper != nil {
		//panic(fmt.Sprint("adding ", helper.Name.Name, " to functions for ", s.name))
		s.methods = append(s.methods, helper)
	}
	return []spec{s}, nil
}
Example #3
0
// Generate a type declaration for the built-in binary values, along with
// marshal/unmarshal methods for them.
func (cfg *Config) genBinarySpec(t xsd.Builtin) ([]spec, error) {
	cfg.debugf("generating Go source for binary type %q", xsd.XMLName(t).Local)
	s := spec{
		expr:    builtinExpr(t),
		name:    xsd.XMLName(t).Local,
		xsdType: t,
	}
	marshal := gen.Func("MarshalText").Receiver("b "+s.name).Returns("[]byte", "error")
	unmarshal := gen.Func("UnmarshalText").Receiver("b " + s.name).Args("text []byte").
		Returns("err error")

	switch t {
	case xsd.HexBinary:
		unmarshal.Body(`
			*b, err = hex.DecodeString(string(text))
			return err
		`)
		marshal.Body(`
			n := hex.EncodedLen([]byte(b))
			buf := make([]byte, n)
			hex.Encode(buf, []byte(b))
			return buf, nil
		`)
	case xsd.Base64Binary:
		unmarshal.Body(`
			*b, err = base64.StdEncoding.DecodeString(string(text))
			return err
		`)
		marshal.Body(`
			var buf bytes.Buffer
			enc := base64.NewEncoder(base64.StdEncoding, &buf)
			enc.Write([]byte(b))
			enc.Close()
			return buf.Bytes()
		`)
	}
	marshalFn, err := marshal.Decl()
	if err != nil {
		return nil, fmt.Errorf("MarshalText %s: %v", s.name, err)
	}
	unmarshalFn, err := unmarshal.Decl()
	if err != nil {
		return nil, fmt.Errorf("UnmarshalText %s: %v", s.name, err)
	}
	s.methods = append(s.methods, unmarshalFn, marshalFn)
	return []spec{s}, nil
}
Example #4
0
// Generate a type declaration for a <list> type, along with marshal/unmarshal
// methods.
func (cfg *Config) genSimpleListSpec(t *xsd.SimpleType) ([]spec, error) {
	cfg.debugf("generating Go source for simple list %q", xsd.XMLName(t).Local)
	expr, err := cfg.expr(t.Base)
	if err != nil {
		return nil, err
	}
	s := spec{
		name:    cfg.typeName(t.Name),
		expr:    expr,
		xsdType: t,
	}
	marshal, err := gen.Func("MarshalText").
		Receiver("x *"+s.name).
		Returns("[]byte", "error").
		Body(`
			return nil, nil
		`).Decl()

	if err != nil {
		return nil, fmt.Errorf("MarshalText %s: %v", s.name, err)
	}

	unmarshal, err := gen.Func("UnmarshalText").
		Receiver("x *" + s.name).
		Args("text []byte").
		Returns("error").
		Body(`
			return nil
		`).Decl()

	if err != nil {
		return nil, fmt.Errorf("UnmarshalText %s: %v", s.name, err)
	}

	s.methods = append(s.methods, marshal, unmarshal)
	return []spec{s}, nil
}
Example #5
0
func (cfg *Config) addStandardHelpers() {
	fns := []*gen.Function{
		gen.Func("_unmarshalTime").
			Args("text []byte", "t *time.Time", "format string").
			Returns("err error").
			Body(`
				s := string(bytes.TrimSpace(text))
				*t, err = time.Parse(format, s)
				if _, ok := err.(*time.ParseError); ok {
					*t, err = time.Parse(format + "Z07:00", s)
				}
				return err
			`),
	}
	for _, fn := range fns {
		x, err := fn.Decl()
		if err != nil {
			// These functions are all bundled with the program, and
			// should never fail to parse
			panic("failed to create helper function: " + err.Error())
		}
		cfg.helpers = append(cfg.helpers, x)
	}
}
Example #6
0
// SOAP arrays (and other similar types) are complex types with a single
// plural element. We add a post-processing step to flatten it out and provide
// marshal/unmarshal methods.
func (cfg *Config) soapArrayToSlice(s spec) spec {
	str, ok := s.expr.(*ast.StructType)
	if !ok {
		return s
	}
	if len(str.Fields.List) != 1 {
		return s
	}
	slice, ok := str.Fields.List[0].Type.(*ast.ArrayType)
	if !ok {
		return s
	}
	cfg.debugf("flattening single-element slice struct type %s to []%v", s.name, slice.Elt)
	tag := gen.TagKey(str.Fields.List[0], "xml")
	xmltag := xml.Name{"", ",any"}

	if tag != "" {
		parts := strings.Split(tag, ",")
		if len(parts) > 0 {
			fields := strings.Fields(parts[0])
			if len(fields) > 0 {
				xmltag.Local = fields[len(fields)-1]
			}
			if len(fields) > 1 {
				xmltag.Space = fields[0]
			}
		}
	}

	itemType := gen.ExprString(slice.Elt)
	unmarshal, err := gen.Func("UnmarshalXML").
		Receiver("a *"+s.name).
		Args("d *xml.Decoder", "start xml.StartElement").
		Returns("err error").
		Body(`
			var tok xml.Token
			var itemTag = xml.Name{%q, %q}
			
			for tok, err = d.Token(); err == nil; tok, err = d.Token() {
				if tok, ok := tok.(xml.StartElement); ok {
					var item %s
					if itemTag.Local != ",any" && itemTag != tok.Name {
						err = d.Skip()
						continue
					}
					if err = d.DecodeElement(&item, &tok); err == nil {
						*a = append(*a, item)
					}
				}
				if _, ok := tok.(xml.EndElement); ok {
					break
				}
			}
			return err
		`, xmltag.Space, xmltag.Local, itemType).Decl()
	if err != nil {
		cfg.logf("error generating UnmarshalXML method of %s: %v", s.name, err)
		return s
	}

	marshal, err := gen.Func("MarshalXML").
		Receiver("a *"+s.name).
		Args("e *xml.Encoder", "start xml.StartElement").
		Returns("error").
		Body(`
			tag := xml.StartElement{Name: xml.Name{"", "item"}}
			for _, elt := range *a {
				if err := e.EncodeElement(elt, tag); err != nil {
					return err
				}
			}
			return nil
		`).Decl()
	if err != nil {
		cfg.logf("error generating MarshalXML method of %s: %v", s.name, err)
		return s
	}

	s.expr = slice
	s.methods = append(s.methods, marshal)
	s.methods = append(s.methods, unmarshal)
	if helper := cfg.helper("_unmarshalArray"); helper != nil {
		s.methods = append(s.methods, helper)
	}
	return s
}