func parsePlural(el *xmltree.Element) bool { if min := parseInt(el.Attr("", "minOccurs")); min > 1 { return true } else if max := parseInt(el.Attr("", "maxOccurs")); max < 0 || max > 1 { return true } return false }
func parseAnyElement(ns string, el *xmltree.Element) Element { var base Type = AnyType typeattr := el.Attr("", "type") if typeattr != "" { base = parseType(el.Resolve(typeattr)) } return Element{ Plural: parsePlural(el), Type: base, Wildcard: true, } }
// http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-complexType func (s *Schema) parseComplexType(root *xmltree.Element) *ComplexType { var t ComplexType var doc annotation t.Name = root.ResolveDefault(root.Attr("", "name"), s.TargetNS) t.Abstract = parseBool(root.Attr("", "abstract")) // We set this special attribute in a pre-processing step. t.Anonymous = (root.Attr("", "_isAnonymous") == "true") walk(root, func(el *xmltree.Element) { switch el.Name.Local { case "annotation": doc = doc.append(parseAnnotation(el)) case "simpleContent": t.parseSimpleContent(s.TargetNS, el) case "complexContent": t.parseComplexContent(s.TargetNS, el) default: // a complex type defined without any simpleContent or // complexContent is interpreted as shorthand for complex // content that restricts anyType. children := root.Children root.Children = nil restrict := *root restrict.StartElement = xml.StartElement{ Name: xml.Name{schemaNS, "restriction"}, } restrict.SetAttr("", "base", restrict.Prefix(AnyType.Name())) restrict.Children = children content := *root content.StartElement = xml.StartElement{ Name: xml.Name{schemaNS, "complexContent"}, } content.Children = []xmltree.Element{restrict} root.Children = []xmltree.Element{content} t.parseComplexContent(s.TargetNS, &content) } }) t.Doc += string(doc) return &t }
func lookupTargetNS(data ...[]byte) []string { var result []string for _, doc := range data { tree, err := xmltree.Parse(doc) if err != nil { continue } outer := xmltree.Element{ Children: []xmltree.Element{*tree}, } elts := outer.Search("http://www.w3.org/2001/XMLSchema", "schema") for _, el := range elts { ns := el.Attr("", "targetNamespace") if ns != "" { result = append(result, ns) } } } return result }
func (s *Schema) parseSimpleType(root *xmltree.Element) *SimpleType { var t SimpleType var doc annotation t.Name = root.ResolveDefault(root.Attr("", "name"), s.TargetNS) t.Anonymous = (root.Attr("", "_isAnonymous") == "true") walk(root, func(el *xmltree.Element) { switch el.Name.Local { case "restriction": t.Base = parseType(el.Resolve(el.Attr("", "base"))) t.Restriction = parseSimpleRestriction(el) case "list": t.Base = parseType(el.Resolve(el.Attr("", "itemType"))) t.List = true case "union": for _, name := range strings.Fields(el.Attr("", "memberTypes")) { type_ := parseType(el.Resolve(name)) t.Union = append(t.Union, type_) } case "annotation": doc = doc.append(parseAnnotation(el)) } }) t.Doc = string(doc) return &t }
func parseAnnotation(el *xmltree.Element) (doc annotation) { if err := el.Unmarshal(&doc); err != nil { stop(err.Error()) } return doc }
func parseAttribute(ns string, el *xmltree.Element) Attribute { var a Attribute var doc annotation // Non-QName xml attributes explicitly do *not* have a namespace. if name := el.Attr("", "name"); strings.Contains(name, ":") { a.Name = el.Resolve(el.Attr("", "name")) } else { a.Name.Local = name } a.Type = parseType(el.Resolve(el.Attr("", "type"))) a.Default = el.Attr("", "default") a.Scope = el.Scope walk(el, func(el *xmltree.Element) { if el.Name.Local == "annotation" { doc = doc.append(parseAnnotation(el)) } }) a.Doc = string(doc) // Other attributes could be useful later. One such attribute is // wsdl:arrayType. a.Attr = el.StartElement.Attr return a }
func parseElement(ns string, el *xmltree.Element) Element { var doc annotation e := Element{ Name: el.ResolveDefault(el.Attr("", "name"), ns), Type: parseType(el.Resolve(el.Attr("", "type"))), Default: el.Attr("", "default"), Abstract: parseBool(el.Attr("", "abstract")), Nillable: parseBool(el.Attr("", "nillable")), Optional: (el.Attr("", "use") == "optional"), Plural: parsePlural(el), Scope: el.Scope, } walk(el, func(el *xmltree.Element) { if el.Name.Local == "annotation" { doc = doc.append(parseAnnotation(el)) } }) e.Doc = string(doc) e.Attr = el.StartElement.Attr return e }
func (s *Schema) parse(root *xmltree.Element, extra map[string]*xmltree.Element) (err error) { defer catchParseError(&err) // First pass: name all anonymous types with placeholder names. var ( typeCounter int updateAttr string accum bool ) for _, el := range root.SearchFunc(hasAnonymousType) { if el.Name.Space != schemaNS { continue } switch el.Name.Local { case "element", "attribute": updateAttr = "type" accum = false case "list": updateAttr = "itemType" accum = false case "restriction": updateAttr = "base" accum = false case "union": updateAttr = "memberTypes" accum = true default: return fmt.Errorf("Did not expect <%s> to have an anonymous type", el.Prefix(el.Name)) } for _, t := range el.SearchFunc(isType) { typeCounter++ name := anonTypeName(typeCounter, s.TargetNS) qname := el.Prefix(name) t.SetAttr("", "name", name.Local) t.SetAttr("", "_isAnonymous", "true") if accum { qname = el.Attr("", updateAttr) + " " + qname } el.SetAttr("", updateAttr, qname) if !accum { break } } } // Second pass: de-reference all group/element/attribute references. for _, el := range root.SearchFunc(hasAttr("", "ref")) { var found bool sameType := and(isElem(el.Name.Space, el.Name.Local), hasAttr("", "name")) if el.Name.Space != schemaNS { continue } ref := el.ResolveDefault(el.Attr("", "ref"), s.TargetNS) for ns, doc := range extra { for _, real := range doc.SearchFunc(sameType) { name := real.ResolveDefault(real.Attr("", "name"), ns) if name == ref { extraAttr := el.StartElement.Attr el.Content = real.Content el.StartElement = real.StartElement el.Children = real.Children el.Scope = *real.JoinScope(&el.Scope) // In XML Schema, it is valid to // reference another element and // at the same time add attributes // to it. We handle this by merging // the attributes of elements and // their references. for _, attr := range extraAttr { if attr.Name.Local == "ref" { continue } el.SetAttr(attr.Name.Space, attr.Name.Local, attr.Value) } found = true break } } } if !found { return fmt.Errorf("could not dereference %s %s %s", el.Name.Local, el.Resolve(el.Attr("", "ref")).Space, el.Resolve(el.Attr("", "ref")).Local) } } // Final pass: parse all type declarations. for _, el := range root.Search(schemaNS, "complexType") { t := s.parseComplexType(el) s.Types[t.Name] = t } for _, el := range root.Search(schemaNS, "simpleType") { t := s.parseSimpleType(el) s.Types[t.Name] = t } return err }