diff --git a/xsd/xsd.go b/xsd/xsd.go index ef3d35b..491afa2 100644 --- a/xsd/xsd.go +++ b/xsd/xsd.go @@ -317,6 +317,34 @@ func XMLName(t Type) xml.Name { panic(fmt.Sprintf("xsd: unexpected xsd.Type %[1]T %[1]v passed to XMLName", t)) } +func XMLNamePtr(t Type) *xml.Name { + switch t := t.(type) { + case *SimpleType: + return &t.Name + case *ComplexType: + return &t.Name + case Builtin: + return &xml.Name{Space: t.Name().Space, Local: t.Name().Local} + case linkedType: + return &xml.Name{Space: t.Space, Local: t.Local} + } + panic(fmt.Sprintf("xsd: unexpected xsd.Type %[1]T %[1]v passed to XMLNamePtr", t)) +} + +func Elements(t Type) *[]Element { + switch t := t.(type) { + case *SimpleType: + return &[]Element{} + case *ComplexType: + return &t.Elements + case Builtin: + return &[]Element{} + case linkedType: + return &[]Element{} + } + panic(fmt.Sprintf("xsd: unexpected xsd.Type %[1]T %[1]v passed to Elements", t)) +} + // Base returns the base type that a Type is derived from. // If the value is of type Builtin, Base will return nil. func Base(t Type) Type { diff --git a/xsdgen/cli.go b/xsdgen/cli.go index e2ac7a0..c7d758a 100644 --- a/xsdgen/cli.go +++ b/xsdgen/cli.go @@ -55,6 +55,7 @@ func (cfg *Config) GenCode(data ...[]byte) (*Code, error) { // GenAST creates an *ast.File containing type declarations and // associated methods based on a set of XML schema. func (cfg *Config) GenAST(files ...string) (*ast.File, error) { + cfg.filesRead = make(map[string]bool) data, err := cfg.readFiles(files...) code, err := cfg.GenCode(data...) if err != nil { @@ -66,6 +67,10 @@ func (cfg *Config) GenAST(files ...string) (*ast.File, error) { func (cfg *Config) readFiles(files ...string) ([][]byte, error) { data := make([][]byte, 0, len(files)) for _, filename := range files { + if _, ok := cfg.filesRead[filename]; ok { + // skip reading the file again + continue + } path, err := filepath.Abs(filename) if err != nil { return nil, err @@ -75,6 +80,7 @@ func (cfg *Config) readFiles(files ...string) ([][]byte, error) { return nil, err } cfg.debugf("read %s(%s)", path, filename) + cfg.filesRead[filename] = true if cfg.followImports { dir := filepath.Dir(path) importedRefs, err := xsd.Imports(b) diff --git a/xsdgen/config.go b/xsdgen/config.go index a14b6be..360aac8 100644 --- a/xsdgen/config.go +++ b/xsdgen/config.go @@ -46,6 +46,9 @@ type Config struct { // if populated, only types that are true in this map // will be selected. allowTypes map[xml.Name]bool + + // keep track of files that are read already to avoid reading it again + filesRead map[string]bool } type typeTransform func(xsd.Schema, xsd.Type) xsd.Type diff --git a/xsdgen/xsdgen.go b/xsdgen/xsdgen.go index e2c1e3c..a9bd539 100644 --- a/xsdgen/xsdgen.go +++ b/xsdgen/xsdgen.go @@ -172,7 +172,30 @@ func (cfg *Config) gen(primaries, deps []xsd.Schema) (*Code, error) { } } + rename := make(map[xml.Name]string) + types := make(map[string]string) + + // Check for any duplicate names between namespaces + for i, primary := range primaries { + for k, _ := range primary.Types { + if !strings.HasPrefix(k.Local, "_") && types[k.Local] != "" && types[k.Local] != k.Space { + rename[k] = k.Local + fmt.Sprint(i) + } else { + types[k.Local] = k.Space + } + } + } + for _, primary := range primaries { + // Rename duplicate types so they generate properly + for _, v := range primary.Types { + for i := range *xsd.Elements(v) { + if val, exists := rename[*xsd.XMLNamePtr((*xsd.Elements(v))[i].Type)]; exists { + xsd.XMLNamePtr((*xsd.Elements(v))[i].Type).Local = val + } + } + } + cfg.debugf("flattening type hierarchy for schema %q", primary.TargetNS) types := cfg.flatten(primary.Types) types = cfg.expandComplexTypes(types)