/* * Pass0: Collect globally (schema) scoped enumerations. */ private void ParseEnumeration0(XmlSchemaSimpleType simpleType, String name, ElementsSubset es) { if (simpleType.Name == null || simpleType.Name == "") { // locally scoped simpleType enumeration on an element or attribute. We don't care about these here. return; } else { // globally scoped simpleType at the schema level -- this is what we're searching for here name = simpleType.Name; } if (simpleType.Content is XmlSchemaSimpleTypeRestriction) { XmlSchemaSimpleTypeRestriction restriction = (XmlSchemaSimpleTypeRestriction)simpleType.Content; for (int j = 0; j < restriction.Facets.Count; j++) { if (restriction.Facets[j] is XmlSchemaEnumerationFacet) { if (!es.SimpleTypes.ContainsKey(name)) es.SimpleTypes.Add(name, name); return; } } } }
/* * Pass0: Gather enumeration types */ private void ParseAttributesPass0(XmlSchemaObjectCollection attributes, ElementsSubset es) { for (int i = 0; i < attributes.Count; i++) { if (attributes[i] is XmlSchemaAttributeGroupRef) { XmlSchemaAttributeGroupRef attributeGroupRef = (XmlSchemaAttributeGroupRef)attributes[i]; XmlSchemaAttributeGroup attributeGroup = (XmlSchemaAttributeGroup)schema.AttributeGroups[attributeGroupRef.RefName]; ParseAttributesPass0(attributeGroup.Attributes, es); } else if (attributes[i] is XmlSchemaAttribute) { XmlSchemaAttribute attributeRef = (XmlSchemaAttribute)attributes[i]; XmlSchemaAttribute attribute = (XmlSchemaAttribute)schema.Attributes[attributeRef.QualifiedName]; if (attribute == null) return; //locally definied attributes -- we don't care about these if (attribute.AttributeType is XmlSchemaSimpleType) { // build SimpleType enumeration if needed XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)attribute.AttributeType; ParseEnumeration0(simpleType, attribute.Name, es); } } } }
//******************************************************************************************** //******************************************************************************************** // PASS ZERO ROUTINES -- this is only used when someone uses the /E option for telling the code // generator to only generate classes and types for a specific set of elements from the schema. // Purpose of this is to fill out the ElementsSubset referenced complexTypes and simpleTypes. // Point is to find just the global elements and types referenced by the passed in element list // and build code for those elements. This will result in a smaller compiled assembly. //******************************************************************************************** //******************************************************************************************** /// <summary> /// Pass0. Collect info on classes, forward declarations, collections (ArrayList subclasses), and any local enumerations (globals have already been added). /// </summary> /// <param name="complex">Instance of a ComplexType</param> /// <param name="qname">QualifiedName object for schema element or schema type</param> private void ParseComplexTypePass0(XmlSchemaComplexType complex, String dotnetClassName, XmlQualifiedName qname, string currentNamespace, ElementsSubset es) { ArrayList childClasses = new ArrayList(); XmlSchemaComplexType baseSchema = complex.BaseSchemaType as XmlSchemaComplexType; if (baseSchema != null) { if (!es.ComplexTypes.ContainsKey(baseSchema.QualifiedName.Name)) { es.ComplexTypes.Add(baseSchema.QualifiedName.Name, baseSchema.QualifiedName.Name); ParseComplexTypePass0(baseSchema, baseSchema.QualifiedName.Name, baseSchema.QualifiedName, baseSchema.QualifiedName.Name, es); } } // Gather referenced enumeration types if any ParseAttributesPass0(complex.Attributes, es); if (complex.Particle is XmlSchemaGroupBase) { ParseGroupBasePass0((XmlSchemaGroupBase)complex.Particle, dotnetClassName, childClasses, complex.QualifiedName.Namespace, currentNamespace, es); } else if (complex.Particle is XmlSchemaGroupRef) { XmlSchemaGroup group = (XmlSchemaGroup)schema.Groups[((XmlSchemaGroupRef)complex.Particle).RefName]; ParseGroupBasePass0(group.Particle, dotnetClassName, childClasses, complex.QualifiedName.Namespace, currentNamespace, es); } else if (complex.ContentModel is XmlSchemaSimpleContent) { XmlSchemaSimpleContent simpleContent = (XmlSchemaSimpleContent)complex.ContentModel; if (simpleContent.Content is XmlSchemaSimpleContentRestriction) { XmlSchemaSimpleContentRestriction contentRestriction = (XmlSchemaSimpleContentRestriction)simpleContent.Content; ParseAttributesPass0(contentRestriction.Attributes, es); } else if (simpleContent.Content is XmlSchemaSimpleContentExtension) { XmlSchemaSimpleContentExtension contentExtension = (XmlSchemaSimpleContentExtension)simpleContent.Content; ParseAttributesPass0(contentExtension.Attributes, es); } } else if (complex.ContentModel is XmlSchemaComplexContent) { XmlSchemaComplexContent complexContent = (XmlSchemaComplexContent)complex.ContentModel; if (complexContent.Content is XmlSchemaComplexContentRestriction) { XmlSchemaComplexContentRestriction contentRestriction = (XmlSchemaComplexContentRestriction)complexContent.Content; if (contentRestriction.Attributes != null) ParseAttributesPass0(contentRestriction.Attributes, es); if (contentRestriction.Particle != null) { if (contentRestriction.Particle is XmlSchemaGroupBase) ParseGroupBasePass0((XmlSchemaGroupBase)contentRestriction.Particle, dotnetClassName, childClasses, complex.QualifiedName.Namespace, currentNamespace, es); else if (contentRestriction.Particle is XmlSchemaGroupRef) { XmlSchemaGroup group = (XmlSchemaGroup)schema.Groups[((XmlSchemaGroupRef)contentRestriction.Particle).RefName]; ParseGroupBasePass0(group.Particle, dotnetClassName, childClasses, complex.QualifiedName.Namespace, currentNamespace, es); } } } else if (complexContent.Content is XmlSchemaComplexContentExtension) { XmlSchemaComplexContentExtension contentExtension = (XmlSchemaComplexContentExtension)complexContent.Content; if (contentExtension.Attributes != null) ParseAttributesPass0(contentExtension.Attributes, es); if (contentExtension.Particle != null) { if (contentExtension.Particle is XmlSchemaGroupBase) ParseGroupBasePass0((XmlSchemaGroupBase)contentExtension.Particle, dotnetClassName, childClasses, complex.QualifiedName.Namespace, currentNamespace, es); else if (contentExtension.Particle is XmlSchemaGroupRef) { XmlSchemaGroup group = (XmlSchemaGroup)schema.Groups[((XmlSchemaGroupRef)contentExtension.Particle).RefName]; ParseGroupBasePass0(group.Particle, dotnetClassName, childClasses, complex.QualifiedName.Namespace, currentNamespace, es); } } } } for (int i = 0; i < childClasses.Count; i++) { ChildComplexType child = (ChildComplexType)childClasses[i]; ParseComplexTypePass0(child.ComplexType, child.DotnetClassName, child.Qname, currentNamespace, es); } }
/* * Pass0. Collect references to globally defined complextypes and simpletypes. */ private void ParseGroupBasePass0(XmlSchemaGroupBase groupBase, String dotnetClassName, ArrayList childClasses, string parentNamespace, string currentNamespace, ElementsSubset es) { for (int i = 0; i < groupBase.Items.Count; i++) { if (groupBase.Items[i] is XmlSchemaElement) { XmlSchemaElement elementRef = (XmlSchemaElement)groupBase.Items[i]; XmlSchemaElement element = (XmlSchemaElement)schema.Elements[elementRef.QualifiedName]; if (element == null) element = elementRef; string ns = element.QualifiedName.Namespace != "" ? element.QualifiedName.Namespace : parentNamespace; if (element.ElementType is XmlSchemaComplexType && element.SchemaTypeName.Namespace != Globals.XSD_NAMESPACE) { XmlSchemaComplexType elementComplex = (XmlSchemaComplexType)element.ElementType; // The complex type is locally defined so a child class needs to be created. if ((element == elementRef) && (schema.SchemaTypes[elementComplex.QualifiedName] == null)) { // recure these later childClasses.Add(new ChildComplexType(elementComplex, element.Name, "", ns, element.QualifiedName)); } if ((schema.Elements[elementRef.QualifiedName] != null) && (elementComplex.Name != null && elementComplex.Name != "")) { // global element who's name and type are set. Both element and complextype are named. if (!es.Elements.ContainsKey(elementRef.QualifiedName.Name)) { // add element and recure it's complextype es.Elements.Add(elementRef.QualifiedName.Name, elementRef.QualifiedName.Name); if (!es.ComplexTypes.ContainsKey(elementComplex.QualifiedName.Name) && !string.IsNullOrEmpty(elementComplex.QualifiedName.Name)) { es.ComplexTypes.Add(elementComplex.QualifiedName.Name, elementComplex.QualifiedName.Name); ParseComplexTypePass0(elementComplex, elementComplex.QualifiedName.Name, elementComplex.QualifiedName, elementComplex.QualifiedName.Namespace, es); } } } else if (elementComplex.Name != null && elementComplex.Name != "") { // globally defined named schema type if (!es.ComplexTypes.ContainsKey(elementComplex.QualifiedName.Name)) { es.ComplexTypes.Add(elementComplex.QualifiedName.Name, elementComplex.QualifiedName.Name); ParseComplexTypePass0(elementComplex, elementComplex.QualifiedName.Name, elementComplex.QualifiedName, elementComplex.QualifiedName.Namespace, es); } } else { // global element complexType -- element is named, but complex type is not if (!es.Elements.ContainsKey(elementRef.QualifiedName.Name)) { // add element and recure it's complextype es.Elements.Add(elementRef.QualifiedName.Name, elementRef.QualifiedName.Name); ParseComplexTypePass0(elementComplex, elementRef.QualifiedName.Name, elementRef.QualifiedName, elementRef.QualifiedName.Namespace, es); } } } else { // not a ComplexType string xsdTypeName = element.SchemaTypeName.Name; string clrTypeName = code.FrameworkTypeMapping(xsdTypeName); // build SimpleType enumeration if needed if (element.ElementType is XmlSchemaSimpleType) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)element.ElementType; ParseEnumeration0(simpleType, element.Name, es); } } } else if (groupBase.Items[i] is XmlSchemaGroupRef) { XmlSchemaGroup group = (XmlSchemaGroup)schema.Groups[((XmlSchemaGroupRef)groupBase.Items[i]).RefName]; ParseGroupBasePass0(group.Particle, dotnetClassName, childClasses, parentNamespace, currentNamespace, es); } else if (groupBase.Items[i] is XmlSchemaGroupBase) { // Particle inside a particle : ie. <xsd:sequence> <xsd:choice/> </xsd:sequence> ParseGroupBasePass0((XmlSchemaGroupBase)groupBase.Items[i], dotnetClassName, childClasses, parentNamespace, currentNamespace, es); } } }
/// <summary> /// Executes the code generator. Called from either the command line exe or the VS.NET wizard. Only public function. /// </summary> /// <param name="xsdFile">Path to the XSD file stored on disk</param> /// <param name="language">Language for generated code</param> /// <param name="genNamespace">.NET namespace containing the generated types</param> /// <param name="fileName">File to be generated. If null, namespace name is used</param> /// <param name="outputLocation">Location for the generated output file</param> /// <param name="constructRequiredSchema">Build a schema compliancy function -- MakeSchemaCompliant -- into each class</param> /// <param name="depthFirstTraversalHooks">Add DepthFirstTraversal hooks to fire custom DepthFirstTraversal events on each generated class</param> /// <param name="defaultInitialization">Set schema default values in class constructors</param> /// <param name="separateImportedNamespaces">Searate out imported namespaces into their own source files. Default is all types in one file.</param> /// <param name="namespaceTable">Namespace map table. Null if no imported namespaces exist</param> /// <param name="filenameTable">Filenames matching the namespaceTable. Null if no imported namespaces exist -- and optional.</param> /// <param name="partialKeyword">put the .NET 2.0 partial keyword on every class</param> /// <param name="optionEElements"></param> /// <param name="acordLookupCodesFile">ACORD lookup codes file -- public</param> /// <param name="acordLookupCodesFilePrivate">ACORD lookup codes file -- private</param> /// <returns>result string</returns> public string[] Execute(string xsdFile, Language language, string genNamespace, string fileName, string outputLocation, bool constructRequiredSchema, bool depthFirstTraversalHooks, bool defaultInitialization, ref Hashtable namespaceTable, Hashtable filenameTable, bool partialKeyword, List<string> optionEElements, string acordLookupCodesFile, string acordLookupCodesFilePrivate) { FileStream schemaFile = null; try { schemaFile = new FileStream(xsdFile, FileMode.Open, FileAccess.Read); if (schemaFile == null) throw new XSDObjectGenException("Could not open the XSD schema file: " + xsdFile); schema = XmlSchema.Read(schemaFile, new ValidationEventHandler(ShowCompileError)); schema.Compile(new ValidationEventHandler(ShowCompileError)); elementFormDefault = schema.ElementFormDefault; attributeFormDefault = schema.AttributeFormDefault; if (language == Language.VB) { code = (LanguageBase)new VBTemplate(); } else if (language == Language.CS) { code = (LanguageBase)new CSharpTemplate(); } else { throw new XSDObjectGenException(string.Format("Language {0} not supported.", language.ToString())); } if (!string.IsNullOrEmpty(acordLookupCodesFile)) { acordLookup = new XmlDocument(); try { acordLookup.Load(acordLookupCodesFile); } catch (Exception) { throw new XSDObjectGenException("Bad ACORD lookup file path or file"); } } if (!string.IsNullOrEmpty(acordLookupCodesFilePrivate)) { acordLookupPrivate = new XmlDocument(); try { acordLookupPrivate.Load(acordLookupCodesFilePrivate); } catch (Exception) { throw new XSDObjectGenException("Bad ACORD private codes lookup file path or file"); } } optionDefaultInitialization = defaultInitialization; optionConstructRequiredSchema = constructRequiredSchema; optionDepthFirstTraversalHooks = depthFirstTraversalHooks; LanguageBase.partialClasses = partialKeyword; globalComplexTypeClasses = new Hashtable(); globalQualifiedComplexTypeClasses = new Hashtable(); globalQualifiedAbstractTypeClasses = new Hashtable(); enumerations = new Hashtable(); enumerableClasses = new Hashtable(); classesReferencingAbstractTypes = new Hashtable(); ArrayList parentClassStack = new ArrayList(); // arraylist to collect a stack of parent owner .NET classes for nested complexTypes Globals.globalSchemaTypeTable.Clear(); // clear globals schema type table as it's a global object created at assembly load scope Globals.globalSeparateImportedNamespaces = false; // means we have imported namespace and will have multiple source files Globals.globalClrNamespaceList.Clear(); // Get list of all imported schemas -- to be used only if separateImportedNamespaces = true // Add the main xsd namespace. If separateImportedNamespaces is false, there will be only // one .net file generated with all of the types from all the xsd namespaces. Otherwise multiple files. // First namespace in the list is the namespace for the base leaf schema -- for which code is being generated. ArrayList references = new ArrayList(); if (namespaceTable != null) { if (schema.TargetNamespace != null) genNamespace = (string)namespaceTable[schema.TargetNamespace]; // in case it was changed while changing imported ns names else genNamespace = (string)namespaceTable[""]; } if (schema.TargetNamespace != null) { namespaces.Add(schema.TargetNamespace, references); namespacesList.Add(schema.TargetNamespace); xsdNsToClrNs.Add(schema.TargetNamespace, genNamespace); } else { // targetNamespace can be null namespaces.Add("", references); namespacesList.Add(""); xsdNsToClrNs.Add("", genNamespace); } // Break down the imported namespaces if any. There will be one .cs or .vb file generated for each xsd namespace. // Set the globalSelectedImportedNamespaces flag to determine if we generate just one file or many files. RecurseImportedNamespaces(schema, references); if (namespacesList.Count > 1 && namespaceTable == null) { namespaceTable = xsdNsToClrNs; return null; } else if (namespaceTable != null) { xsdNsToClrNs = namespaceTable; } foreach (string clrNs in xsdNsToClrNs.Values) { Globals.globalClrNamespaceList.Add(clrNs); } /*******/ // Walk through, prepare and build the global class collections from the xsd complexTypes // contained in the global scope -- child of the <schema> element. Point of this stuff is // to handle all the combination of naming conflicts. // Build and populate these structures // globalQualifiedAbstractTypeClasses // globalQualifiedComplexTypeClasses // globalComplexTypeClasses // globalSchemaTypeTable /*******/ foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) { if (schemaType is XmlSchemaComplexType) { string dotnetTypeName = CalculateUniqueTypeOrFieldName(schemaType.Name, schemaType.QualifiedName.Namespace, globalComplexTypeClasses); globalComplexTypeClasses.Add(dotnetTypeName, schemaType.Name); GlobalSchemaType gst = new GlobalSchemaType(schemaType.QualifiedName.Namespace, schemaType.Name, GlobalXsdType.ComplexType, (string)xsdNsToClrNs[schemaType.QualifiedName.Namespace], dotnetTypeName); Globals.globalSchemaTypeTable.Add(gst.XsdNamespaceAndTypeName, gst); if (globalQualifiedComplexTypeClasses[schemaType.QualifiedName] == null) { globalQualifiedComplexTypeClasses.Add(schemaType.QualifiedName, dotnetTypeName); // collect the list of types marked as abstract. This is needed to later add XmlIncludeAttribute to their usage. if (((XmlSchemaComplexType)schemaType).IsAbstract) { globalQualifiedAbstractTypeClasses.Add(schemaType.QualifiedName, new Hashtable()); } } } } foreach (XmlSchemaElement element in schema.Elements.Values) { if (element.ElementType is XmlSchemaComplexType) { XmlSchemaComplexType complexType = (XmlSchemaComplexType)element.ElementType; string dotnetTypeName = element.Name; if (globalComplexTypeClasses[element.Name] == null) { // Each namespace can have one global schema level CT (schema type) and global schema level element WITH THE SAME NAME. // We get here assuming a complexType with the same name hasn't already been added (which will be a .NET class). dotnetTypeName = CalculateUniqueTypeOrFieldName(element.Name, element.QualifiedName.Namespace, globalComplexTypeClasses); globalComplexTypeClasses.Add(dotnetTypeName, element.Name); } GlobalSchemaType gst = new GlobalSchemaType(element.QualifiedName.Namespace, element.Name, GlobalXsdType.Element, (string)xsdNsToClrNs[element.QualifiedName.Namespace], dotnetTypeName); Globals.globalSchemaTypeTable.Add(gst.XsdNamespaceAndTypeName, gst); if (globalQualifiedComplexTypeClasses[element.QualifiedName] == null) { globalQualifiedComplexTypeClasses.Add(element.QualifiedName, dotnetTypeName); } else { // Each namespace can have one global schema level CT (schema type) and global schema level element WITH THE SAME NAME. // Hence schemaType.QualifiedName == element.QualifiedName for this scenerio. Use a special Globals.ELELENT_DELIMINATOR to flag this. globalQualifiedComplexTypeClasses.Add(Globals.ELELENT_DELIMINATOR + element.QualifiedName, dotnetTypeName); } } else if (element.ElementType is XmlSchemaSimpleType) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)element.ElementType; if (IsEnumeration(simpleType)) { GlobalSchemaType gst = new GlobalSchemaType(element.QualifiedName.Namespace, element.Name, GlobalXsdType.Enum, (string)xsdNsToClrNs[element.QualifiedName.Namespace], element.Name); Globals.globalSchemaTypeTable.Add(gst.XsdNamespaceAndTypeName, gst); } } } foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) { if (schemaType is XmlSchemaSimpleType) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)schemaType; if (IsEnumeration(simpleType)) { GlobalSchemaType gst = new GlobalSchemaType(simpleType.QualifiedName.Namespace, simpleType.Name, GlobalXsdType.Enum, (string)xsdNsToClrNs[simpleType.QualifiedName.Namespace], simpleType.Name); if (Globals.globalSchemaTypeTable[gst.XsdNamespaceAndTypeName] == null) Globals.globalSchemaTypeTable.Add(gst.XsdNamespaceAndTypeName, gst); } } } outFiles = new string[namespaces.Count]; int iFiles = 0; // Walk through all of the schema namespaces and generate .net types for (int i = 0; i < namespacesList.Count; i++) { /*******/ // Pass1: // Walk through and add collect infomation for forward declarations (where required), // collection classes, and enumerations. The code will be added later. // There are two kinds of complex types. // 1. ComplexTypes globally defined and "named" in the schema that are not tied to an XML element name. // 2. Globally defined xsd:elements that are complex types and are linked to an xml element // First build classes for the global types, then traverse the elements and add those types. // Note: There are actually 3 different types of ComplexTypes. The third is a locally defined // ComplexType that are not a child of <schema>. These are collected later in the childClasses // collection. /*******/ string ns = (string)namespacesList[i]; enumerations.Clear(); bool optionE = optionEElements != null && optionEElements.Count > 0; ElementsSubset es = new ElementsSubset(); // Pass0. Uses Pass0 routines. Only used if Option E is sent in. if (optionE) { // Handle special optionE processing. Parse down and build the references for this element foreach (XmlSchemaElement element in schema.Elements.Values) { if (optionEElements.Contains(element.QualifiedName.Name)) { XmlSchemaComplexType complexType = (XmlSchemaComplexType)element.ElementType; if (!es.Elements.ContainsKey(element.QualifiedName.Name)) { es.Elements.Add(element.QualifiedName.Name, element.QualifiedName.Name); if (!string.IsNullOrEmpty(complexType.QualifiedName.Name) && !es.ComplexTypes.ContainsKey(complexType.QualifiedName.Name)) es.ComplexTypes.Add(complexType.QualifiedName.Name, complexType.QualifiedName.Name); ParseComplexTypePass0(complexType, element.QualifiedName.Name, element.QualifiedName, element.QualifiedName.Namespace, es); } } } } // Pass1 officially starts here. Uses Pass1 routines. foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) { // Add global schema type enumerations. Locally scoped ones will be added later during ParseComplexTypePass1. if (schemaType is XmlSchemaSimpleType && (!Globals.globalSeparateImportedNamespaces || ns == schemaType.QualifiedName.Namespace)) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)schemaType; if (optionE && !es.SimpleTypes.ContainsKey(simpleType.Name)) continue; // only build specific classes if (IsEnumeration(simpleType)) { string globalEnumName = ParseEnumeration1(simpleType, simpleType.Name); } } } foreach (XmlSchemaElement element in schema.Elements.Values) { // Add global schema element enumerations. Locally scoped ones will be added later during ParseComplexTypePass1. if (element.ElementType is XmlSchemaSimpleType && (!Globals.globalSeparateImportedNamespaces || ns == element.QualifiedName.Namespace)) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)element.ElementType; if (optionE && !es.SimpleTypes.ContainsKey(simpleType.Name)) continue; // only build specific classes if (IsEnumeration(simpleType)) { string globalEnumName = ParseEnumeration1(simpleType, element.Name); } } } // now deep-dive and parse into each global schema element and type foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) { if (schemaType is XmlSchemaComplexType && (!Globals.globalSeparateImportedNamespaces || ns == schemaType.QualifiedName.Namespace)) { if (optionE && !es.ComplexTypes.ContainsKey(schemaType.QualifiedName.Name)) continue; // only build specific classes parentClassStack.Clear(); string dotnetTypeName = (string)globalQualifiedComplexTypeClasses[schemaType.QualifiedName]; ParseComplexTypePass1((XmlSchemaComplexType)schemaType, dotnetTypeName, parentClassStack, schemaType.QualifiedName, ns); } } foreach (XmlSchemaElement element in schema.Elements.Values) { if (element.ElementType is XmlSchemaComplexType && (!Globals.globalSeparateImportedNamespaces || ns == element.QualifiedName.Namespace) && (element.SchemaTypeName.Name == null || element.SchemaTypeName.Name == "")) { if (optionE && !es.Elements.ContainsKey(element.QualifiedName.Name)) continue; // only build specific classes // If element.SchemaTypeName.Name is set, then this is a global element with it's type set to a schema type. // i.e. <xs:element name="DataServiceResponse" type="DataServiceResponseType" /> // This results in a simple class in code which inherits from the SchemaType and no child fields -- so don't do anything further parentClassStack.Clear(); XmlSchemaComplexType complexType = (XmlSchemaComplexType)element.ElementType; string dotnetTypeName = GlobalElementToClrMap(element.QualifiedName); ParseComplexTypePass1(complexType, dotnetTypeName, parentClassStack, element.QualifiedName, ns); } } // **************************** // Start writing out code // **************************** FileStream classFile = null; if (outputLocation == "" || outputLocation == null) outFiles[iFiles] = ""; else if (outputLocation[outputLocation.Length - 1] == '\\') outFiles[iFiles] = outputLocation; else if (outputLocation[outputLocation.Length - 1] != '\\') outFiles[iFiles] = outputLocation + "\\"; string codeFile; string targetNamespace; string dotnetNamespace; if (i == 0 && namespacesList.Count == 1) // no imported namespaces { // first namespace in the list is the main xsd namespace we're building from targetNamespace = ns; codeFile = genNamespace; // this is the default filename if not overriden with /f or /z dotnetNamespace = genNamespace; // use "fileName" for the main xsd generated .net file, if passed in from UI if (fileName != null && fileName != "") codeFile = fileName; } else { // imported namespaces targetNamespace = ns; dotnetNamespace = (string)xsdNsToClrNs[targetNamespace]; codeFile = (string)xsdNsToClrNs[targetNamespace]; // this is the default filename if not overriden with /f or /z if (filenameTable != null && filenameTable.Count > 0) codeFile = (string)filenameTable[targetNamespace]; // /z override } if (language == Language.VB) { if (!codeFile.ToLower().EndsWith(".vb")) codeFile = codeFile + ".vb"; } else //(language == Language.CS) { if (!codeFile.ToLower().EndsWith(".cs")) codeFile = codeFile + ".cs"; } outFiles[iFiles] = outFiles[iFiles] + codeFile; classFile = new FileStream(outFiles[iFiles], FileMode.Create); outStream = new StreamWriter(classFile); // Add namespace, using statement, forward declarations, and enumerations string schemaFileName = schemaFile.Name; int slashIndex = 0; while ((slashIndex = schemaFileName.IndexOf("\\")) >= 0) schemaFileName = schemaFileName.Substring(slashIndex + 1); if (genNamespace == null || genNamespace == "") { // the VB case where explicit namespaces are not in the code code.NamespaceHeaderCode(outStream, genNamespace, schemaFileName, null, targetNamespace, enumerations, optionDepthFirstTraversalHooks, (ArrayList)namespaces[targetNamespace]); } else { code.NamespaceHeaderCode(outStream, dotnetNamespace, schemaFileName, null, targetNamespace, enumerations, optionDepthFirstTraversalHooks, (ArrayList)namespaces[targetNamespace]); } // Re-add all the globally scoped enumerations to the enumerations list. This is done again so in Pass2 we handle locally scoped // simpleType enumerations that have duplicate names. We go through the name calculation again for duplicate enums -- as a way // to match up the enum type name (when duplicates occur) with the enum field variables. The assumption is made that the parsing // order of Pass1 is equal to that of Pass2 -- otherwise the duplicate locally scoped enums won't match their respective // enumeration type that was collected during Pass1. // Note that in most schemas there won't be locally scoped duplicate enumeration names -- so this really won't matter. And if there is, // it's probably not a good schema design. enumerations.Clear(); // clear enumerations list as they will be recollected to properly account for locally scoped duplicates foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) { if (schemaType is XmlSchemaSimpleType && (!Globals.globalSeparateImportedNamespaces || ns == schemaType.QualifiedName.Namespace)) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)schemaType; if (optionE && !es.SimpleTypes.ContainsKey(simpleType.Name)) continue; // only build specific classes if (IsEnumeration(simpleType) && (!Globals.globalSeparateImportedNamespaces || ns == simpleType.QualifiedName.Namespace)) enumerations.Add(LanguageBase.ReplaceInvalidChars(simpleType.Name), ""); } } foreach (XmlSchemaElement element in schema.Elements.Values) { if (element.ElementType is XmlSchemaSimpleType && (!Globals.globalSeparateImportedNamespaces || ns == element.QualifiedName.Namespace)) { XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)element.ElementType; if (optionE && !es.SimpleTypes.ContainsKey(simpleType.Name)) continue; // only build specific classes if (IsEnumeration(simpleType) && (!Globals.globalSeparateImportedNamespaces || ns == element.QualifiedName.Namespace)) { if (enumerations[LanguageBase.ReplaceInvalidChars(element.Name)] == null) enumerations.Add(LanguageBase.ReplaceInvalidChars(element.Name), ""); } } } /*******/ // Pass2: // Walk through and build code for all complex types (these will be classes in .NET) // First add the globally defined classes, then add the classes for the schema level // ComplexType elements. /*******/ foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) { if (schemaType is XmlSchemaComplexType && (!Globals.globalSeparateImportedNamespaces || ns == schemaType.QualifiedName.Namespace)) { if (optionE && !es.ComplexTypes.ContainsKey(schemaType.QualifiedName.Name)) continue; // only build specific classes parentClassStack.Clear(); string dotnetTypeName = (string)globalQualifiedComplexTypeClasses[schemaType.QualifiedName]; // If schema type and a global element have the same name, don't create a class for the element // This will be a special case where the schema type .net class has both XmlTypeAttribute and XmlElementAttribute. bool globalElementAndSchemaTypeHaveSameName = false; if (schema.Elements[schemaType.QualifiedName] != null) globalElementAndSchemaTypeHaveSameName = true; ParseComplexTypePass2((XmlSchemaComplexType)schemaType, dotnetTypeName, schemaType.Name, true, false, schemaType.QualifiedName.Namespace, parentClassStack, "", "", false, globalElementAndSchemaTypeHaveSameName); } } foreach (XmlSchemaElement element in schema.Elements.Values) { if (element.ElementType is XmlSchemaComplexType && (!Globals.globalSeparateImportedNamespaces || ns == element.QualifiedName.Namespace)) { if (optionE && !es.Elements.ContainsKey(element.QualifiedName.Name)) continue; // only build specific classes parentClassStack.Clear(); string dotnetTypeName = GlobalElementToClrMap(element.QualifiedName); string elementSchemaType = ""; if (element.SchemaTypeName.Name != null && element.SchemaTypeName.Name != "") { // global element with it's type set to a schema type elementSchemaType = (string)globalQualifiedComplexTypeClasses[element.SchemaTypeName]; // If schema type and global element have the same name, don't create a class for the element // This will be a special case where the schema type .net class has both XmlTypeAttribute and XmlElementAttribute. if (element.QualifiedName == element.SchemaTypeName) continue; } // // don't generate a class for root level schema-typed elements that are abstract -- since these classes can't be created externally. // if (elementSchemaType != "" && element.IsAbstract) // continue; ParseComplexTypePass2((XmlSchemaComplexType)element.ElementType, dotnetTypeName, element.Name, false, false, element.QualifiedName.Namespace, parentClassStack, elementSchemaType, element.SchemaTypeName.Namespace, element.IsNillable, false); } } code.NamespaceTrailerCode(outStream, dotnetNamespace); outStream.Flush(); iFiles++; outStream.Close(); schemaFile.Close(); // Finished writing out .net for a xsd namespace } // End of foreach imported namespace System.Diagnostics.EventLog.WriteEntry("XSDSchemaParser", String.Format("Done. Writing files")); return outFiles; } catch (XSDObjectGenException e) { // code logic specific exceptions throw e; } catch (FileNotFoundException e) { // inbound xsd file cannot be loaded throw new XSDObjectGenException(e.Message); } catch (UnauthorizedAccessException e) { // security throw new XSDObjectGenException(e.Message); } catch (XmlSchemaException e) { // xsd schema compiler exception. xsd has some type of error. if (outStream != null) { outStream.WriteLine(); outStream.WriteLine("LineNumber = {0}", e.LineNumber); outStream.WriteLine("LinePosition = {0}", e.LinePosition); outStream.WriteLine("Message = {0}", e.Message); outStream.WriteLine("Source = {0}", e.Source); } throw new XSDObjectGenException(string.Format( ".NET Framework XSD Schema compile error.\nError occurred : {0}", e.Message)); } catch (XmlException e) { // bad xml document -- schema cannot be read because it's not valid xml if (outStream != null) { outStream.WriteLine(); outStream.WriteLine("LineNumber = {0}", e.LineNumber); outStream.WriteLine("LinePosition = {0}", e.LinePosition); outStream.WriteLine("Message = {0}", e.Message); outStream.WriteLine("Source = {0}", e.Source); } throw new XSDObjectGenException(string.Format( ".NET Framework could not read the XSD file. Bad XML file.\nError occurred : {0}", e.Message)); } catch (Exception e) { // unexpected exceptions System.Diagnostics.EventLog.WriteEntry("Unexpected XSDObjectGen exception", e.Message, System.Diagnostics.EventLogEntryType.Error); if (outStream != null) { outStream.WriteLine(); outStream.WriteLine("Error message : {0}", e.Message); outStream.WriteLine("Source : {0}", e.Source); outStream.WriteLine("Stack : {0}", e.StackTrace); } throw new Exception("Unexpected XSDObjectGen Exception", e); } finally { if (outStream != null) outStream.Close(); if (schemaFile != null) schemaFile.Close(); } }