Beispiel #1
0
// makePath finds or creates a tree of Scanners.
// It returns the leaf node Scanner for the path or an error.
func (s *Scanner) makePath(path string) (*Scanner, error) {
	names := strings.SplitN(path, ">", 2)
	fields := strings.Fields(names[0])
	var name xml.Name
	switch len(fields) {
	case 0:
		if len(names) > 1 {
			return nil, ErrInvalidPath
		}
		return s, nil
	case 1:
		name.Local = fields[0]
	case 2:
		name.Space = fields[0]
		name.Local = fields[1]
	default:
		return nil, ErrInvalidPath
	}
	s2, ok := s.tree[name]
	if !ok {
		s2 = NewScanner()
		s.tree[name] = s2
	}
	if len(names) == 1 {
		return s2.makePath("")
	}
	return s2.makePath(names[1])
}
Beispiel #2
0
// SOAP arrays are declared as follows (unimportant fields ellided):
//
// 	<xs:complexType name="Array">
// 	  <xs:attribute name="arrayType" type="xs:string" />
// 	  <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" />
// 	</xs:complexType>
//
// Then schemas that want to declare a fixed-type soap array do so like this:
//
// 	<xs:complexType name="IntArray">
// 	  <xs:complexContent>
// 	    <xs:restriction base="soapenc:Array>
// 	      <xs:attribute ref="soapenc:arrayType" wsdl:arrayType="xs:int[]" />
// 	    </xs:restriction>
// 	  </xs:complexContent>
// 	</xs:complexType>
//
// XML Schema is wonderful, aint it?
func (cfg *Config) parseSOAPArrayType(s xsd.Schema, t xsd.Type) xsd.Type {
	const soapenc = "http://schemas.xmlsoap.org/soap/encoding/"
	const wsdl = "http://schemas.xmlsoap.org/wsdl/"
	var itemType xml.Name

	c, ok := t.(*xsd.ComplexType)
	if !ok {
		return t
	}
	var attr []xsd.Attribute
	for _, v := range c.Attributes {
		if v.Name.Local != "arrayType" {
			attr = append(attr, v)
			continue
		}
		for _, a := range v.Attr {
			if (a.Name != xml.Name{wsdl, "arrayType"}) {
				continue
			}
			itemType = v.Resolve(a.Value)
			break
		}
		break
	}
	if itemType.Local == "" {
		return c
	}
	itemType.Local = strings.TrimSpace(itemType.Local)
	itemType.Local = strings.TrimSuffix(itemType.Local, "[]")
	if b := s.FindType(itemType); b != nil {
		c = cfg.overrideWildcardType(c, b)
	} else {
		cfg.logf("could not lookup item type %q in namespace %q",
			itemType.Local, itemType.Space)
	}

	// Have to remove arrayType from the "base" type, without affecting
	// others inheriting from this type.
	basep, ok := c.Base.(*xsd.ComplexType)
	if !ok {
		cfg.logf("type %s derives from non-complexType %s", c.Name.Local, xsd.XMLName(c.Base).Local)
		return c
	}
	base := *basep
	base.Attributes = make([]xsd.Attribute, 0, len(basep.Attributes)-1)
	for _, v := range basep.Attributes {
		if v.Name.Local != "arrayType" {
			base.Attributes = append(base.Attributes, v)
		}
	}
	c.Base = &base
	c.Attributes = attr
	return c
}
Beispiel #3
0
// Unmarshal parses the XML encoding of the Element and stores the result
// in the value pointed to by v. Unmarshal follows the same rules as
// xml.Unmarshal, but only parses the portion of the XML document
// contained by the Element.
func (el *Element) Unmarshal(v interface{}) error {
	start := el.StartElement
	for _, ns := range el.ns {
		name := xml.Name{"", "xmlns"}
		if ns.Local != "" {
			name.Local += ":" + ns.Local
		}
		start.Attr = append(start.Attr, xml.Attr{name, ns.Space})
	}
	if start.Name.Space != "" {
		for i := len(el.ns) - 1; i >= 0; i-- {
			if el.ns[i].Space == start.Name.Space {
				start.Name.Space = ""
				start.Name.Local = el.ns[i].Local + ":" + start.Name.Local
				break
			}
		}
		if start.Name.Space != "" {
			return fmt.Errorf("Could not find namespace prefix for %q when decoding %s",
				start.Name.Space, start.Name.Local)
		}
	}

	var buf bytes.Buffer
	e := xml.NewEncoder(&buf)

	if err := e.EncodeToken(start); err != nil {
		return err
	}
	if err := e.Flush(); err != nil {
		return err
	}

	// BUG(droyo) The Unmarshal method unmarshals an XML fragment as it
	// was returned by the Parse method; further modifications to a tree of
	// Elements are ignored by the Unmarshal method.
	buf.Write(el.Content)
	if err := e.EncodeToken(xml.EndElement{start.Name}); err != nil {
		return err
	}
	if err := e.Flush(); err != nil {
		return err
	}
	return xml.Unmarshal(buf.Bytes(), v)
}
Beispiel #4
0
func xfFunction(f *xpFilt, n *parser.Node) error {
	spl := strings.Split(n.Val.Val, ":")
	var name xml.Name
	if len(spl) == 1 {
		name.Local = spl[0]
	} else {
		name.Space = f.ns[spl[0]]
		name.Local = spl[1]
	}
	fn, ok := intfns.BuiltIn[name]
	if !ok {
		fn, ok = f.fns[name]
	}

	if ok {
		args := []tree.Result{}
		param := n.Left

		for param != nil {
			pf := xpFilt{
				t:         f.t,
				ctx:       f.ctx,
				ns:        f.ns,
				ctxPos:    f.ctxPos,
				ctxSize:   f.ctxSize,
				fns:       f.fns,
				variables: f.variables,
			}
			res, err := exec(&pf, param.Left)
			if err != nil {
				return err
			}

			args = append(args, res)
			param = param.Right
		}

		filt, err := fn.Call(tree.Ctx{NodeSet: f.ctx.(tree.NodeSet), Size: f.ctxSize, Pos: f.ctxPos + 1}, args...)
		f.ctx = filt
		return err
	}

	return fmt.Errorf("Unknown function: %s", n.Val.Val)
}
Beispiel #5
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
}